pax_global_header 0000666 0000000 0000000 00000000064 12260363731 0014515 g ustar 00root root 0000000 0000000 52 comment=d97bd72879939ebf314637068218335d5005f3fe
gqrx-sdr-2.2.0.74.d97bd7/ 0000775 0000000 0000000 00000000000 12260363731 0014515 5 ustar 00root root 0000000 0000000 gqrx-sdr-2.2.0.74.d97bd7/.gitignore 0000664 0000000 0000000 00000000111 12260363731 0016476 0 ustar 00root root 0000000 0000000 build/
Makefile
gqrx.pro.user*
*.o
moc_*
qrc_*
ui_*
.DS_Store
Info.plist
gqrx-sdr-2.2.0.74.d97bd7/COPYING 0000664 0000000 0000000 00000104513 12260363731 0015554 0 ustar 00root root 0000000 0000000 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
.
gqrx-sdr-2.2.0.74.d97bd7/README-mac.txt 0000664 0000000 0000000 00000001730 12260363731 0016752 0 ustar 00root root 0000000 0000000 This is Gqrx 2.2 for Mac.
Gqrx is a simple software defined radio receiver application for Linux and Mac, powered by GNU Radio and the Qt GUI toolkit.
This binary distribution includes support for the following devices:
- Funcube Dongle Pro and Pro+
- RTL-SDR (via USB or TCP)
- USRP devices from Ettus Research
- HackRF Jawbreaker
- OsmoSDR
Plug in your device and start Gqrx. Your device should be detected and shown in the drop-down list. Note that some input devices (e.g. hackrf) will always be present in the drop-down list even if you don't have plugged in.
The bundle also includes various command line utilities that come with the driver libraries. They are located in Gqrx.app/Contents/MacOS/
Gqrx can also be started from the command line with various options that are useful for manipulating the configuration. Run 'Gqrx.app/Contents/MacOS/Gqrx -h' to get a list of options.
Gqrx 2.2 for Mac should be considered beta software. Feedback is welcome: http://gqrx.dk/
gqrx-sdr-2.2.0.74.d97bd7/README.md 0000664 0000000 0000000 00000011344 12260363731 0015777 0 ustar 00root root 0000000 0000000 Gqrx
====
Gqrx is an experimental software defined radio receiver implemented using GNU Radio and the Qt GUI toolkit. Currently it works on Linux and Mac and supports the following devices:
- Funcube Dongle Pro and Pro+
- RTL2832U-based DVB-T dongles (rtlsdr via USB and TCP)
- OsmoSDR
- USRP
- HackRF Jawbreaker
- Nuand bladeRF
- RFspace SDR-IQ, SDR-IP and NetSDR
- any other device supported by the gr-osmosdr library
Gqrx can operate as a traditional AM/FM/SSB receiver with audio output or as an FFT-only instrument.
Download
--------
Gqrx is distributed as source code package and binaries for Linux and Mac. Please see http://gqrx.dk/download for a list of official and third party download resources.
Usage
-----
The first time you start gqrx it will open a device configuration dialog. Supported devices that are connected to the computer are discovered automatically and you can select any of them in the drop-down list.
If you don't see your device listed in the drop-down list it could be because:
- The driver has not included in a binary distribution
- The udev rule has not been properly configured
You can test your device first with rtl_test, qthid, or uhd_usrp_probe that come with the respective packages.
Gqrx supports multiple configurations and sessions if you have several devices or if you want to use the same device under different configurations. You can load a configuration from the GUI or using the -c command line argument. See "gqrx --help" for a complete list of command line arguments.
Tutorials and howtos are being written and published on the website
http://gqrx.dk/
Known problems
--------------
See the bug tracker on Github: https://github.com/csete/gqrx/issues
Getting help and reporting bugs
-------------------------------
There is now a Google group for discussing anything related to Gqrx: https://groups.google.com/forum/#!forum/gqrx
This includes getting help with installation and troubleshooting. Please remember to provide detailed description of your problem, your setup, what steps you followed, etc.
Installation from source
------------------------
The source code is hosted on Github: https://github.com/csete/gqrx
To compile gqrx from source you need the following dependencies:
- GNU Radio 3.7 with the following components:
- gnuradio-runtime
- gnuradio-analog
- gnuradio-blocks
- gnuradio-filter
- gnuradio-fft
- gnuradio-audio
- The gr-iqbalance library (optional)
- At least one of:
- Funcube Dongle Pro driver via gnuradio-fcd
- UHD driver via gnuradio-uhd
- Funcube Dongle Pro+ driver from https://github.com/dl1ksv/gr-fcdproplus
- RTL-SDR driver from http://cgit.osmocom.org/cgit/rtl-sdr/
- OsmoSDR driver from http://cgit.osmocom.org/cgit/osmo-sdr/
- HackRF Jawbreaker driver from http://greatscottgadgets.com/hackrf/
- gnuradio-osmosdr from http://cgit.osmocom.org/cgit/gr-osmosdr/
- pulseaudio (Linux only and optional)
- Qt 4.7 or later and optionally Qt Creator (gqrx works with Qt 5)
Gqrx comes with a simple qmake build setup. It can be compiled from within Qt Creator or in a terminal:
$ git clone https://github.com/csete/gqrx.git gqrx.git
$ cd gqrx.git
$ mkdir build
$ cd build
$ qmake ..
$ make
To build in debug mode add "CONFIG+=debug" to the qmake step above. There are also some other qmake options, see the gqrx.pro file.
Credits and License
-------------------
Gqrx is designed and written by Alexandru Csete OZ9AEC, and it is licensed under the GNU General Public License.
Some of the source files were adopted from Cutesdr by Moe Weatley and these come with a BSD license.
Following people and organisations have contributed:
Alex Grinkov:
- FM stereo demodulator.
Anthony Willard:
- Various fixes and improvements
Elias Önal:
- Building Gqrx on Mac OS X.
- Crash recovery dialog.
Frank Brickle, AB2KT:
Bob McGwier, N4HY:
- Noise blanker (from dttsp).
Göran Weinholt, SM6-8239:
- Various GUI improvements.
Jiří Pinkava:
- Port to gnuradio 3.7 API.
Kobra @ Xiatek:
- Auto squelch.
Michael Dickens:
- Bugfixes on OSX.
Moe Weatley:
- FFT plotter and waterfall.
- Frequency selector.
- Signal strength indicator.
- AGC
Nadeem Hasan:
- Bug fixes.
Nokia:
- QtColorPicker widget.
Stefano Leucci:
- Peak detection and hold for the FFT plot.
Vesa Solonen:
- DC removal in AM demodulator.
Vincent Pelletier
- Initial work on the horizontal zooming / scrolling.
Will Scales
- Bug fixes.
Also thanks to Volker Schroer and Alexey Bazhin for bringing Funcube Dongle Pro+ support to GNU Radio and Gqrx.
Some of the icons are from the GNOME and Tango icon themes. The scope.svg icon is based on the utilities-system-monitor.svg icon from the Mint-X icon theme licensed under GNU GPL.
Let me know if somebody or someting is missing from the list!
Alex OZ9AEC
gqrx-sdr-2.2.0.74.d97bd7/applications/ 0000775 0000000 0000000 00000000000 12260363731 0017203 5 ustar 00root root 0000000 0000000 gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/ 0000775 0000000 0000000 00000000000 12260363731 0020164 5 ustar 00root root 0000000 0000000 gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/gqrx.h 0000664 0000000 0000000 00000002106 12260363731 0021315 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2012 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#define GQRX_ORG_NAME "gqrx"
#define GQRX_ORG_DOMAIN "gqrx.org"
#define GQRX_APP_NAME "gqrx"
#define GQRX_CONFIG_VERSION 2
//#define GQRX_VERSION_MAJOR 2
//#define GQRX_VERSION_MINOR 0
//#define GQRX_VERSION_MICRO 0
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/main.cpp 0000664 0000000 0000000 00000011304 12260363731 0021613 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2011-2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include "mainwindow.h"
#include "gqrx.h"
#include
#include
namespace po = boost::program_options;
static void reset_conf(const QString &file_name);
int main(int argc, char *argv[])
{
QString cfg_file;
std::string conf;
bool clierr=false;
bool edit_conf = false;
QApplication a(argc, argv);
QCoreApplication::setOrganizationName(GQRX_ORG_NAME);
QCoreApplication::setOrganizationDomain(GQRX_ORG_DOMAIN);
QCoreApplication::setApplicationName(GQRX_APP_NAME);
QCoreApplication::setApplicationVersion(VERSION);
// setup controlport via environment variables
// see http://lists.gnu.org/archive/html/discuss-gnuradio/2013-05/msg00270.html
// Note: tried using gr::prefs().save() but that doesn't have effect until the next time
if (qputenv("GR_CONF_CONTROLPORT_ON", "False"))
qDebug() << "Controlport disabled";
else
qDebug() << "Failed to disable controlport";
//#ifdef GQRX_OS_MACX
#ifdef WITH_PORTAUDIO
// FIXME: This should be user configurable although for now
// the audio-osx-source is useless and the only way to use the
// Funcube Dongle Pro and Pro+ is via portaudio.
if (qputenv("GR_CONF_AUDIO_AUDIO_MODULE", "portaudio"))
qDebug() << "GR_CONF_AUDIO_AUDIO_MODULE set to portaudio";
else
qDebug() << "Failed to set GR_CONF_AUDIO_AUDIO_MODULE=portaudio";
#endif
// setup the program options
po::options_description desc("Command line options");
desc.add_options()
("help,h", "This help message")
("conf,c", po::value(&conf), "Start with this config file")
("edit,e", "Edit the config file before using it")
("reset,r", "Reset configuration file")
;
po::variables_map vm;
try
{
po::store(po::parse_command_line(argc, argv, desc), vm);
}
catch(const boost::program_options::invalid_command_line_syntax& ex)
{
/* happens if e.g. -c without file name */
clierr = true;
}
catch(const boost::program_options::unknown_option& ex)
{
/* happens if e.g. -c without file name */
clierr = true;
}
po::notify(vm);
// print the help message
if (vm.count("help") || clierr)
{
std::cout << "Gqrx software defined radio receiver " << VERSION << std::endl << desc << std::endl;
return 1;
}
if (!conf.empty())
{
cfg_file = QString::fromStdString(conf);
qDebug() << "User specified config file:" << cfg_file;
}
else
{
cfg_file = "default.conf";
qDebug() << "No user supplied config file. Using" << cfg_file;
}
if (vm.count("reset"))
reset_conf(cfg_file);
else if (vm.count("edit"))
edit_conf = true;
// Mainwindow will check whether we have a configuration
// and open the config dialog if there is none or the specified
// file does not exist.
MainWindow w(cfg_file, edit_conf);
if (w.configOk)
{
w.show();
return a.exec();
}
else
{
return 1;
}
}
/*! \brief Reset configuration file specified by file_name. */
static void reset_conf(const QString &file_name)
{
QString cfg_file;
QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME");
if (xdg_dir.isEmpty())
cfg_file = QString("%1/.config/gqrx/%2").arg(QDir::homePath()).arg(file_name);
else
cfg_file = QString("%1/gqrx/%2").arg(xdg_dir.data()).arg(file_name);
if (QFile::exists(cfg_file))
{
if (QFile::remove(cfg_file))
qDebug() << cfg_file << "deleted";
else
qDebug() << "Failed to remove" << cfg_file;
}
else
{
qDebug() << "Cano not delete" << cfg_file << "- file does not exist!";
}
}
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/mainwindow.cpp 0000664 0000000 0000000 00000150112 12260363731 0023044 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2011-2013 Alexandru Csete OZ9AEC.
* Copyright (C) 2013 by Elias Oenal
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "qtgui/ioconfig.h"
#include "mainwindow.h"
/* Qt Designer files */
#include "ui_mainwindow.h"
/* DSP */
#include "receiver.h"
#include "remote_control_settings.h"
MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
QMainWindow(parent),
configOk(true),
ui(new Ui::MainWindow),
d_lnb_lo(0),
d_hw_freq(0),
d_fftAvg(0.5),
d_have_audio(true),
dec_afsk1200(0)
{
ui->setupUi(this);
/* Initialise default configuration directory */
QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME");
if (xdg_dir.isEmpty())
m_cfg_dir = QString("%1/.config/gqrx").arg(QDir::homePath()); // Qt takes care of conversion to native separators
else
m_cfg_dir = QString("%1/gqrx").arg(xdg_dir.data());
setWindowTitle(QString("Gqrx %1").arg(VERSION));
/* frequency control widget */
ui->freqCtrl->setup(10, (quint64) 0, (quint64) 9999e6, 1, UNITS_MHZ);
ui->freqCtrl->setFrequency(144500000);
d_filter_shape = receiver::FILTER_SHAPE_NORMAL;
/* create receiver object */
rx = new receiver("", "");
rx->set_rf_freq(144500000.0f);
// remote controller
remote = new RemoteControl();
/* meter timer */
meter_timer = new QTimer(this);
connect(meter_timer, SIGNAL(timeout()), this, SLOT(meterTimeout()));
/* FFT timer & data */
iq_fft_timer = new QTimer(this);
connect(iq_fft_timer, SIGNAL(timeout()), this, SLOT(iqFftTimeout()));
audio_fft_timer = new QTimer(this);
connect(audio_fft_timer, SIGNAL(timeout()), this, SLOT(audioFftTimeout()));
d_fftData = new std::complex[MAX_FFT_SIZE];
d_realFftData = new double[MAX_FFT_SIZE];
d_pwrFftData = new double[MAX_FFT_SIZE]();
d_iirFftData = new double[MAX_FFT_SIZE];
for (int i = 0; i < MAX_FFT_SIZE; i++)
d_iirFftData[i] = -120.0; // dBFS
/* timer for data decoders */
dec_timer = new QTimer(this);
connect(dec_timer, SIGNAL(timeout()), this, SLOT(decoderTimeout()));
/* create dock widgets */
uiDockRxOpt = new DockRxOpt();
uiDockAudio = new DockAudio();
uiDockInputCtl = new DockInputCtl();
//uiDockIqPlay = new DockIqPlayer();
uiDockFft = new DockFft();
/* Add dock widgets to main window. This should be done even for
dock widgets that are going to be hidden, otherwise they will
end up floating in their own top-level window and can not be
docked to the mainwindow.
*/
addDockWidget(Qt::RightDockWidgetArea, uiDockInputCtl);
addDockWidget(Qt::RightDockWidgetArea, uiDockRxOpt);
tabifyDockWidget(uiDockInputCtl, uiDockRxOpt);
addDockWidget(Qt::RightDockWidgetArea, uiDockAudio);
addDockWidget(Qt::RightDockWidgetArea, uiDockFft);
tabifyDockWidget(uiDockFft, uiDockAudio);
//addDockWidget(Qt::BottomDockWidgetArea, uiDockIqPlay);
/* hide docks that we don't want to show initially */
/** FIXME: Hide them initially but store layout in config **/
// uiDockInputCtl->hide();
// uiDockFft->hide();
//uiDockIqPlay->hide();
/* misc configurations */
//uiDockAudio->setFftRange(0, 8000); // FM
/* Add dock widget actions to View menu. By doing it this way all signal/slot
connections will be established automagially.
*/
ui->menu_View->addAction(uiDockInputCtl->toggleViewAction());
ui->menu_View->addAction(uiDockRxOpt->toggleViewAction());
ui->menu_View->addAction(uiDockAudio->toggleViewAction());
ui->menu_View->addAction(uiDockFft->toggleViewAction());
//ui->menu_View->addAction(uiDockIqPlay->toggleViewAction());
ui->menu_View->addSeparator();
ui->menu_View->addAction(ui->mainToolBar->toggleViewAction());
ui->menu_View->addSeparator();
ui->menu_View->addAction(ui->actionFullScreen);
/* connect signals and slots */
connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), this, SLOT(setNewFrequency(qint64)));
connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), remote, SLOT(setNewFrequency(qint64)));
connect(uiDockInputCtl, SIGNAL(lnbLoChanged(double)), this, SLOT(setLnbLo(double)));
connect(uiDockInputCtl, SIGNAL(gainChanged(QString, double)), this, SLOT(setGain(QString,double)));
connect(uiDockInputCtl, SIGNAL(autoGainChanged(bool)), this, SLOT(setAutoGain(bool)));
connect(uiDockInputCtl, SIGNAL(freqCorrChanged(int)), this, SLOT(setFreqCorr(int)));
connect(uiDockInputCtl, SIGNAL(iqSwapChanged(bool)), this, SLOT(setIqSwap(bool)));
connect(uiDockInputCtl, SIGNAL(dcCancelChanged(bool)), this, SLOT(setDcCancel(bool)));
connect(uiDockInputCtl, SIGNAL(iqBalanceChanged(bool)), this, SLOT(setIqBalance(bool)));
connect(uiDockInputCtl, SIGNAL(ignoreLimitsChanged(bool)), this, SLOT(setIgnoreLimits(bool)));
connect(uiDockInputCtl, SIGNAL(antennaSelected(QString)), this, SLOT(setAntenna(QString)));
connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), this, SLOT(setFilterOffset(qint64)));
connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), remote, SLOT(setFilterOffset(qint64)));
connect(uiDockRxOpt, SIGNAL(demodSelected(int)), this, SLOT(selectDemod(int)));
connect(uiDockRxOpt, SIGNAL(fmMaxdevSelected(float)), this, SLOT(setFmMaxdev(float)));
connect(uiDockRxOpt, SIGNAL(fmEmphSelected(double)), this, SLOT(setFmEmph(double)));
connect(uiDockRxOpt, SIGNAL(amDcrToggled(bool)), this, SLOT(setAmDcr(bool)));
connect(uiDockRxOpt, SIGNAL(agcToggled(bool)), this, SLOT(setAgcOn(bool)));
connect(uiDockRxOpt, SIGNAL(agcHangToggled(bool)), this, SLOT(setAgcHang(bool)));
connect(uiDockRxOpt, SIGNAL(agcThresholdChanged(int)), this, SLOT(setAgcThreshold(int)));
connect(uiDockRxOpt, SIGNAL(agcSlopeChanged(int)), this, SLOT(setAgcSlope(int)));
connect(uiDockRxOpt, SIGNAL(agcGainChanged(int)), this, SLOT(setAgcGain(int)));
connect(uiDockRxOpt, SIGNAL(agcDecayChanged(int)), this, SLOT(setAgcDecay(int)));
connect(uiDockRxOpt, SIGNAL(noiseBlankerChanged(int,bool,float)), this, SLOT(setNoiseBlanker(int,bool,float)));
connect(uiDockRxOpt, SIGNAL(sqlLevelChanged(double)), this, SLOT(setSqlLevel(double)));
connect(uiDockRxOpt, SIGNAL(sqlAutoClicked()), this, SLOT(setSqlLevelAuto()));
connect(uiDockAudio, SIGNAL(audioGainChanged(float)), this, SLOT(setAudioGain(float)));
connect(uiDockAudio, SIGNAL(audioStreamingStarted(QString,int)), this, SLOT(startAudioStream(QString,int)));
connect(uiDockAudio, SIGNAL(audioStreamingStopped()), this, SLOT(stopAudioStreaming()));
connect(uiDockAudio, SIGNAL(audioRecStarted(QString)), this, SLOT(startAudioRec(QString)));
connect(uiDockAudio, SIGNAL(audioRecStopped()), this, SLOT(stopAudioRec()));
connect(uiDockAudio, SIGNAL(audioPlayStarted(QString)), this, SLOT(startAudioPlayback(QString)));
connect(uiDockAudio, SIGNAL(audioPlayStopped()), this, SLOT(stopAudioPlayback()));
connect(uiDockAudio, SIGNAL(fftRateChanged(int)), this, SLOT(setAudioFftRate(int)));
connect(uiDockFft, SIGNAL(fftSizeChanged(int)), this, SLOT(setIqFftSize(int)));
connect(uiDockFft, SIGNAL(fftRateChanged(int)), this, SLOT(setIqFftRate(int)));
connect(uiDockFft, SIGNAL(fftSplitChanged(int)), this, SLOT(setIqFftSplit(int)));
connect(uiDockFft, SIGNAL(fftAvgChanged(double)), this, SLOT(setIqFftAvg(double)));
connect(uiDockFft, SIGNAL(resetFftZoom()), ui->plotter, SLOT(resetHorizontalZoom()));
connect(uiDockFft, SIGNAL(gotoFftCenter()), ui->plotter, SLOT(moveToCenterFreq()));
connect(uiDockFft, SIGNAL(gotoDemodFreq()), ui->plotter, SLOT(moveToDemodFreq()));
connect(uiDockFft, SIGNAL(fftColorChanged(QColor)), this, SLOT(setFftColor(QColor)));
connect(uiDockFft, SIGNAL(fftFillToggled(bool)), this, SLOT(setFftFill(bool)));
connect(uiDockFft, SIGNAL(fftPeakHoldToggled(bool)), this, SLOT(setFftPeakHold(bool)));
connect(uiDockFft, SIGNAL(peakDetectionToggled(bool)), this, SLOT(setPeakDetection(bool)));
connect(remote, SIGNAL(newFilterOffset(qint64)), this, SLOT(setFilterOffset(qint64)));
connect(remote, SIGNAL(newFilterOffset(qint64)), uiDockRxOpt, SLOT(setFilterOffset(qint64)));
connect(remote, SIGNAL(newFrequency(qint64)), this, SLOT(setNewFrequency(qint64)));
// satellite events
connect(remote, SIGNAL(satAosEvent()), uiDockAudio, SLOT(startAudioRecorder()));
connect(remote, SIGNAL(satLosEvent()), uiDockAudio, SLOT(stopAudioRecorder()));
// restore last session
if (!loadConfig(cfgfile, true))
{
// first time config
qDebug() << "Launching I/O device editor";
if (firstTimeConfig() != QDialog::Accepted)
{
qDebug() << "I/O device configuration cancelled.";
configOk = false;
}
else
{
configOk = true;
}
}
else if (edit_conf == true)
{
qDebug() << "Launching I/O device editor";
if (on_actionIoConfig_triggered() != QDialog::Accepted)
{
qDebug() << "I/O device configuration cancelled.";
configOk = false;
}
else
{
configOk = true;
}
}
}
MainWindow::~MainWindow()
{
/* stop and delete timers */
dec_timer->stop();
delete dec_timer;
meter_timer->stop();
delete meter_timer;
iq_fft_timer->stop();
delete iq_fft_timer;
audio_fft_timer->stop();
delete audio_fft_timer;
if (m_settings)
{
m_settings->setValue("configversion", 2);
m_settings->setValue("crashed", false);
// hide toolbar (default=false)
if (ui->mainToolBar->isHidden())
m_settings->setValue("gui/hide_toolbar", true);
else
m_settings->remove("gui/hide_toolbar");
m_settings->setValue("gui/geometry", saveGeometry());
m_settings->setValue("gui/state", saveState());
// save session
storeSession();
m_settings->sync();
delete m_settings;
}
delete ui;
delete uiDockRxOpt;
delete uiDockAudio;
delete uiDockFft;
//delete uiDockIqPlay;
delete uiDockInputCtl;
delete rx;
delete remote;
delete [] d_fftData;
delete [] d_realFftData;
delete [] d_iirFftData;
delete [] d_pwrFftData;
}
/*! \brief Load new configuration.
* \param cfgfile
* \returns True if config is OK, False if not (e.g. no input device specified).
*
* If cfgfile is an absolute path it will be used as is, otherwise it is assumed to be the
* name of a file under m_cfg_dir.
*
* If cfgfile does not exist it will be created.
*
* If no input device is specified, we return false to signal that the I/O configuration
* dialog should be run.
*
* FIXME: Refactor.
*/
bool MainWindow::loadConfig(const QString cfgfile, bool check_crash)
{
bool conf_ok = false;
bool skip_loading_cfg = false;
qDebug() << "Loading configuration from:" << cfgfile;
if (m_settings)
delete m_settings;
if (QDir::isAbsolutePath(cfgfile))
m_settings = new QSettings(cfgfile, QSettings::IniFormat);
else
m_settings = new QSettings(QString("%1/%2").arg(m_cfg_dir).arg(cfgfile), QSettings::IniFormat);
qDebug() << "Configuration file:" << m_settings->fileName();
if (check_crash)
{
if (m_settings->value("crashed", false).toBool())
{
qDebug() << "Crash guard triggered!" << endl;
QMessageBox* askUserAboutConfig =
new QMessageBox(QMessageBox::Warning, tr("Crash Detected!"),
tr("Gqrx has detected problems with the current configuration. "
"Loading the configuration again could cause the application to crash.
"
"Do you want to edit the settings?
"),
QMessageBox::Yes | QMessageBox::No);
askUserAboutConfig->setDefaultButton(QMessageBox::Yes);
askUserAboutConfig->setTextFormat(Qt::RichText);
askUserAboutConfig->exec();
if (askUserAboutConfig->result() == QMessageBox::Yes)
skip_loading_cfg = true;
delete askUserAboutConfig;
}
else
{
m_settings->setValue("crashed", true); // clean exit will set this to FALSE
m_settings->sync();
}
}
if (skip_loading_cfg)
return false;
emit configChanged(m_settings);
// manual reconf (FIXME: check status)
bool conv_ok = false;
// hide toolbar
bool bool_val = m_settings->value("gui/hide_toolbar", false).toBool();
if (bool_val)
ui->mainToolBar->hide();
// main window settings
restoreGeometry(m_settings->value("gui/geometry", saveGeometry()).toByteArray());
restoreState(m_settings->value("gui/state", saveState()).toByteArray());
QString indev = m_settings->value("input/device", "").toString();
if (!indev.isEmpty())
{
conf_ok = true;
rx->set_input_device(indev.toStdString());
// Update window title
QRegExp regexp("'([a-zA-Z0-9 \\-\\_\\/\\.\\,\\(\\)]+)'");
QString devlabel;
if (regexp.indexIn(indev, 0) != -1)
devlabel = regexp.cap(1);
else
devlabel = indev; //"Unknown";
setWindowTitle(QString("Gqrx %1 - %2").arg(VERSION).arg(devlabel));
// Add available antenna connectors to the UI
std::vector antennas = rx->get_antennas();
uiDockInputCtl->setAntennas(antennas);
// update gain stages
updateGainStages();
}
QString outdev = m_settings->value("output/device", "").toString();
rx->set_output_device(outdev.toStdString());
int sr = m_settings->value("input/sample_rate", 0).toInt(&conv_ok);
if (conv_ok && (sr > 0))
{
double actual_rate = rx->set_input_rate(sr);
qDebug() << "Requested sample rate:" << sr;
qDebug() << "Actual sample rate :" << QString("%1").arg(actual_rate, 0, 'f', 6);
uiDockRxOpt->setFilterOffsetRange((qint64)(0.9*actual_rate));
ui->plotter->setSampleRate(actual_rate);
ui->plotter->setSpanFreq((quint32)actual_rate);
remote->setBandwidth(sr);
}
qint64 bw = m_settings->value("input/bandwidth", 0).toInt(&conv_ok);
if (conv_ok)
{
// set analog bw even if 0 since for some devices 0 Hz means "auto"
double actual_bw = rx->set_analog_bandwidth((double)bw);
qDebug() << "Requested bandwidth:" << bw << "Hz";
qDebug() << "Actual bandwidth :" << actual_bw << "Hz";
}
uiDockInputCtl->readSettings(m_settings);
uiDockRxOpt->readSettings(m_settings);
uiDockFft->readSettings(m_settings);
uiDockAudio->readSettings(m_settings);
ui->freqCtrl->setFrequency(m_settings->value("input/frequency", 144500000).toLongLong(&conv_ok));
setNewFrequency(ui->freqCtrl->getFrequency()); // ensure all GUI and RF is updated
remote->readSettings(m_settings);
return conf_ok;
}
/*! \brief Save current configuration to a file.
* \param cfgfile
* \returns True if the operation was successful.
*
* If cfgfile is an absolute path it will be used as is, otherwise it is assumed to be the
* name of a file under m_cfg_dir.
*
* If cfgfile already exists it will be overwritten (we assume that a file selection dialog
* has already asked for confirmation of overwrite.
*
* Since QSettings does not support "save as" we do this by copying the current
* settings to a new file.
*/
bool MainWindow::saveConfig(const QString cfgfile)
{
QString oldfile = m_settings->fileName();
QString newfile;
qDebug() << "Saving configuration to:" << cfgfile;
m_settings->sync();
if (QDir::isAbsolutePath(cfgfile))
newfile = cfgfile;
else
newfile = QString("%1/%2").arg(m_cfg_dir).arg(cfgfile);
if (QFile::exists(newfile))
{
qDebug() << "File" << newfile << "already exists => DELETING...";
if (QFile::remove(newfile))
qDebug() << "Deleted" << newfile;
else
qDebug() << "Failed to delete" << newfile;
}
if (QFile::copy(oldfile, newfile))
{
// ensure that old config has crash cleared
m_settings->setValue("crashed", false);
m_settings->sync();
loadConfig(cfgfile, false);
return true;
}
else
{
qDebug() << "Error saving configuration to" << newfile;
return false;
}
}
/*! \brief Store session-related parameters (frequency, gain,...)
*
* This needs to be called when we switch input source, otherwise the
* new source would use the parameters stored on last exit.
*/
void MainWindow::storeSession()
{
if (m_settings)
{
m_settings->setValue("input/frequency", ui->freqCtrl->getFrequency());
uiDockInputCtl->saveSettings(m_settings);
uiDockRxOpt->saveSettings(m_settings);
uiDockFft->saveSettings(m_settings);
uiDockAudio->saveSettings(m_settings);
remote->saveSettings(m_settings);
}
}
/*! \brief Update RF frequency range.
* \param ignore_limits Whether ignore the hardware specd and allow DC-to-light range.
*
* Useful when we read a new configuration with a new input device. This function will
* fetch the frequency range of the receiver and update the frequency control and frequency
* bar widgets.
*
* This function must also be called when the LNB LO has changed.
*/
void MainWindow::updateFrequencyRange(bool ignore_limits)
{
double startd, stopd, stepd;
if (ignore_limits)
{
ui->freqCtrl->setup(10, (quint64) 0, (quint64) 9999e6, 1, UNITS_MHZ);
}
else if (rx->get_rf_range(&startd, &stopd, &stepd) == receiver::STATUS_OK)
{
qDebug() << QString("New frequnecy range: %1 - %2 MHz (step is %3 Hz but we use 1 Hz).").
arg(startd*1.0e-6).arg(stopd*1.0e-6).arg(stepd);
qint64 start = (qint64)startd + d_lnb_lo;
qint64 stop = (qint64)stopd + d_lnb_lo;
ui->freqCtrl->setup(10, start, stop, 1, UNITS_MHZ);
}
else
{
qDebug() << __func__ << "failed fetching new frequency range";
}
}
/*! \brief Update gain stages.
*
* This function fetches a list of available gain stages with their range
* and sends them to the input control UI widget.
*/
void MainWindow::updateGainStages()
{
gain_list_t gain_list;
std::vector gain_names = rx->get_gain_names();
gain_t gain;
for (std::vector::iterator it = gain_names.begin(); it != gain_names.end(); ++it)
{
gain.name = *it;
rx->get_gain_range(gain.name, &gain.start, &gain.stop, &gain.step);
gain.value = rx->get_gain(gain.name);
gain_list.push_back(gain);
}
uiDockInputCtl->setGainStages(gain_list);
}
/*! \brief Slot for receiving frequency change signals.
* \param[in] freq The new frequency.
*
* This slot is connected to the CFreqCtrl::newFrequency() signal and is used
* to set new receive frequency.
*/
void MainWindow::setNewFrequency(qint64 rx_freq)
{
double hw_freq = (double)(rx_freq-d_lnb_lo) - rx->get_filter_offset();
qint64 center_freq = rx_freq - (qint64)rx->get_filter_offset();
d_hw_freq = (qint64)hw_freq;
// set receiver frequency
rx->set_rf_freq(hw_freq);
// update widgets
ui->plotter->setCenterFreq(center_freq);
uiDockRxOpt->setHwFreq(d_hw_freq);
}
/*! \brief Set new LNB LO frequency.
* \param freq_mhz The new frequency in MHz.
*/
void MainWindow::setLnbLo(double freq_mhz)
{
// calculate current RF frequency
qint64 rf_freq = ui->freqCtrl->getFrequency() - d_lnb_lo;
d_lnb_lo = qint64(freq_mhz*1e6);
qDebug() << "New LNB LO:" << d_lnb_lo << "Hz";
// Update ranges and show updated frequency
updateFrequencyRange(uiDockInputCtl->ignoreLimits());
ui->freqCtrl->setFrequency(d_lnb_lo + rf_freq);
ui->plotter->setCenterFreq(d_lnb_lo + d_hw_freq);
}
/*! \brief Select new antenna connector. */
void MainWindow::setAntenna(const QString antenna)
{
qDebug() << "New antenna selected:" << antenna;
rx->set_antenna(antenna.toStdString());
}
/*! \brief Set new channel filter offset.
* \param freq_hz The new filter offset in Hz.
*/
void MainWindow::setFilterOffset(qint64 freq_hz)
{
rx->set_filter_offset((double) freq_hz);
ui->plotter->setFilterOffset(freq_hz);
qint64 rx_freq = d_hw_freq + d_lnb_lo + freq_hz;
ui->freqCtrl->setFrequency(rx_freq);
}
/*! \brief Set a specific gain.
* \param name The name of the gain stage to adjust.
* \param gain The new value.
*/
void MainWindow::setGain(QString name, double gain)
{
rx->set_gain(name.toStdString(), gain);
}
/*! \brief Enable / disable hardware AGC. */
void MainWindow::setAutoGain(bool enabled)
{
rx->set_auto_gain(enabled);
}
/*! \brief Set new frequency offset value.
* \param ppm Frequency correction.
*
* The valid range is between -200 and 200, though this is not checked.
*/
void MainWindow::setFreqCorr(int ppm)
{
qDebug() << __FUNCTION__ << ":" << ppm << "ppm";
rx->set_freq_corr(ppm);
}
/*! \brief Enable/disable I/Q reversion. */
void MainWindow::setIqSwap(bool reversed)
{
rx->set_iq_swap(reversed);
}
/*! \brief Enable/disable automatic DC removal. */
void MainWindow::setDcCancel(bool enabled)
{
rx->set_dc_cancel(enabled);
}
/*! \brief Enable/disable automatic IQ balance. */
void MainWindow::setIqBalance(bool enabled)
{
rx->set_iq_balance(enabled);
}
/*! \brief Ignore hardware limits.
* \param ignore_limits Whether harware limits should be ignored or not.
*
* This slot is triggered when the user changes the "Ignore hardware limits" option.
* It will update the allowed frequency range and also update the current RF center
* frequency, which may change when we swich from ignore to don't ignore.
*/
void MainWindow::setIgnoreLimits(bool ignore_limits)
{
updateFrequencyRange(ignore_limits);
qint64 freq = (qint64)rx->get_rf_freq();
ui->freqCtrl->setFrequency(d_lnb_lo + freq);
// This will ensure that if frequency is clamped, the UI
// will be updated with the correct frequwncy.
freq = ui->freqCtrl->getFrequency();
setNewFrequency(freq);
}
/*! \brief Select new demodulator.
* \param demod New demodulator index.
*
* This slot basically maps the index of the mode selector to receiver::demod
* and configures the default channel filter.
*
*/
void MainWindow::selectDemod(int index)
{
double quad_rate;
float maxdev;
int filter_preset = uiDockRxOpt->currentFilter();
int flo=0, fhi=0, click_res=100;
switch (index) {
case DockRxOpt::MODE_OFF:
/* Spectrum analyzer only */
rx->set_demod(receiver::RX_DEMOD_OFF);
flo = 0;
fhi = 0;
click_res = 100;
break;
case DockRxOpt::MODE_RAW:
/* Raw I/Q */
qDebug() << "RAW I/Q mode not implemented!";
break;
/* AM */
case DockRxOpt::MODE_AM:
rx->set_demod(receiver::RX_DEMOD_AM);
ui->plotter->setDemodRanges(-20000, -250, 250, 20000, true);
uiDockAudio->setFftRange(0,15000);
click_res = 100;
switch (filter_preset)
{
case 0: //wide
flo = -10000;
fhi = 10000;
break;
case 2: // narrow
flo = -2500;
fhi = 2500;
break;
default: // normal
flo = -5000;
fhi = 5000;
break;
}
break;
/* Narrow FM */
case DockRxOpt::MODE_NFM:
rx->set_demod(receiver::RX_DEMOD_NFM);
click_res = 100;
maxdev = uiDockRxOpt->currentMaxdev();
if (maxdev < 20000.0)
{ /** FIXME **/
ui->plotter->setDemodRanges(-25000, -250, 250, 25000, true);
uiDockAudio->setFftRange(0,12000);
switch (filter_preset) {
case 0: //wide
flo = -10000;
fhi = 10000;
break;
case 2: // narrow
flo = -2500;
fhi = 2500;
break;
default: // normal
flo = -5000;
fhi = 5000;
break;
}
}
else
{
ui->plotter->setDemodRanges(-45000, -10000, 10000, 45000, true);
uiDockAudio->setFftRange(0,24000);
switch (filter_preset) {
/** FIXME: not sure about these **/
case 0: //wide
flo = -45000;
fhi = 45000;
break;
case 2: // narrow
flo = -10000;
fhi = 10000;
break;
default: // normal
flo = -35000;
fhi = 35000;
break;
}
}
break;
/* Broadcast FM */
case DockRxOpt::MODE_WFM_MONO:
case DockRxOpt::MODE_WFM_STEREO:
quad_rate = rx->get_input_rate();
if (quad_rate < 200.0e3)
ui->plotter->setDemodRanges(-0.9*quad_rate/2.0, -10000,
10000, 0.9*quad_rate/2.0,
true);
else
ui->plotter->setDemodRanges(-250000, -10000, 10000, 250000, true);
uiDockAudio->setFftRange(0,24000); /** FIXME: get audio rate from rx **/
click_res = 1000;
switch (filter_preset)
{
case 0: //wide
flo = -100000;
fhi = 100000;
break;
case 2: // narrow
flo = -60000;
fhi = 60000;
break;
default: // normal
flo = -80000;
fhi = 80000;
break;
}
if (index == DockRxOpt::MODE_WFM_MONO)
rx->set_demod(receiver::RX_DEMOD_WFM_M);
else
rx->set_demod(receiver::RX_DEMOD_WFM_S);
break;
/* LSB */
case DockRxOpt::MODE_LSB:
rx->set_demod(receiver::RX_DEMOD_SSB);
ui->plotter->setDemodRanges(-10000, -100, -5000, 0, false);
uiDockAudio->setFftRange(0,3500);
click_res = 10;
switch (filter_preset)
{
case 0: //wide
flo = -4100;
fhi = -100;
break;
case 2: // narrow
flo = -1600;
fhi = -200;
break;
default: // normal
flo = -3000;
fhi = -200;
break;
}
break;
/* USB */
case DockRxOpt::MODE_USB:
rx->set_demod(receiver::RX_DEMOD_SSB);
ui->plotter->setDemodRanges(0, 5000, 100, 10000, false);
uiDockAudio->setFftRange(0,3500);
click_res = 10;
switch (filter_preset)
{
case 0: //wide
flo = 100;
fhi = 4100;
break;
case 2: // narrow
flo = 200;
fhi = 1600;
break;
default: // normal
flo = 200;
fhi = 3000;
break;
}
break;
/* CW-L */
case DockRxOpt::MODE_CWL:
rx->set_demod(receiver::RX_DEMOD_SSB);
ui->plotter->setDemodRanges(-10000, -100, -5000, 0, false);
uiDockAudio->setFftRange(0,1500);
click_res = 10;
switch (filter_preset)
{
case 0: //wide
flo = -2300;
fhi = -200;
break;
case 2: // narrow
flo = -900;
fhi = -400;
break;
default: // normal
flo = -1200;
fhi = -200;
break;
}
break;
/* CW-U */
case DockRxOpt::MODE_CWU:
rx->set_demod(receiver::RX_DEMOD_SSB);
ui->plotter->setDemodRanges(0, 5000, 100, 10000, false);
uiDockAudio->setFftRange(0,1500);
click_res = 10;
switch (filter_preset)
{
case 0: //wide
flo = 200;
fhi = 2300;
break;
case 2: // narrow
flo = 400;
fhi = 900;
break;
default: // normal
flo = 200;
fhi = 1200;
break;
}
break;
default:
qDebug() << "Unsupported mode selection: " << index;
flo = -5000;
fhi = 5000;
click_res = 100;
break;
}
qDebug() << "Filter preset for mode" << index << "LO:" << flo << "HI:" << fhi;
ui->plotter->setHiLowCutFrequencies(flo, fhi);
ui->plotter->setClickResolution(click_res);
ui->plotter->setFilterClickResolution(click_res);
rx->set_filter((double)flo, (double)fhi, receiver::FILTER_SHAPE_NORMAL);
d_have_audio = ((index != DockRxOpt::MODE_OFF) && (index != DockRxOpt::MODE_RAW));
}
/*! \brief New FM deviation selected.
* \param max_dev The enw FM deviation.
*/
void MainWindow::setFmMaxdev(float max_dev)
{
qDebug() << "FM MAX_DEV: " << max_dev;
/* receiver will check range */
rx->set_fm_maxdev(max_dev);
/* update filter */
if (max_dev < 20000.0)
{
ui->plotter->setDemodRanges(-25000, -1000, 1000, 25000, true);
ui->plotter->setHiLowCutFrequencies(-5000, 5000);
rx->set_filter(-5000.0, 5000.0, receiver::FILTER_SHAPE_NORMAL);
}
else
{
ui->plotter->setDemodRanges(-45000, -10000, 10000, 45000, true);
ui->plotter->setHiLowCutFrequencies(-35000, 35000);
rx->set_filter(-35000.0, 35000.0, receiver::FILTER_SHAPE_NORMAL);
}
}
/*! \brief New FM de-emphasis time consant selected.
* \param tau The new time constant
*/
void MainWindow::setFmEmph(double tau)
{
qDebug() << "FM TAU: " << tau;
/* receiver will check range */
rx->set_fm_deemph(tau);
}
/*! \brief AM DCR status changed (slot).
* \param enabled Whether DCR is enabled or not.
*/
void MainWindow::setAmDcr(bool enabled)
{
rx->set_am_dcr(enabled);
}
/*! \brief Audio gain changed.
* \param value The new audio gain in dB.
*/
void MainWindow::setAudioGain(float value)
{
rx->set_af_gain(value);
}
/*! \brief Set AGC ON/OFF.
* \param agc_on Whether AGC is ON (true) or OFF (false).
*/
void MainWindow::setAgcOn(bool agc_on)
{
rx->set_agc_on(agc_on);
}
/*! \brief AGC hang ON/OFF.
* \param use_hang Whether to use hang.
*/
void MainWindow::setAgcHang(bool use_hang)
{
rx->set_agc_hang(use_hang);
}
/*! \brief AGC threshold changed.
* \param threshold The new threshold.
*/
void MainWindow::setAgcThreshold(int threshold)
{
rx->set_agc_threshold(threshold);
}
/*! \brief AGC slope factor changed.
* \param factor The new slope factor.
*/
void MainWindow::setAgcSlope(int factor)
{
rx->set_agc_slope(factor);
}
/*! \brief AGC manual gain changed.
* \param gain The new manual gain in dB.
*/
void MainWindow::setAgcGain(int gain)
{
rx->set_agc_manual_gain(gain);
}
/*! \brief AGC decay changed.
* \param factor The new AGC decay.
*/
void MainWindow::setAgcDecay(int msec)
{
rx->set_agc_decay(msec);
}
/*! \brief Noide blanker configuration changed.
* \param nb1 Noise blanker 1 ON/OFF.
* \param nb2 Noise blanker 2 ON/OFF.
* \param threshold Noise blanker threshold.
*/
void MainWindow::setNoiseBlanker(int nbid, bool on, float threshold)
{
qDebug() << "Noise blanker NB:" << nbid << " ON:" << on << "THLD:" << threshold;
rx->set_nb_on(nbid, on);
rx->set_nb_threshold(nbid, threshold);
}
/*! \brief Squelch level changed.
* \param level_db The new squelch level in dBFS.
*/
void MainWindow::setSqlLevel(double level_db)
{
rx->set_sql_level(level_db);
}
/*! \brief Squelch level auto clicked
* \return new squeltch value
*/
double MainWindow::setSqlLevelAuto()
{
double level = rx->get_signal_pwr(true) + 1.0;
setSqlLevel(level);
return level;
}
/*! \brief Signal strength meter timeout */
void MainWindow::meterTimeout()
{
float level;
level = rx->get_signal_pwr(true);
ui->sMeter->setLevel(level);
}
/*! \brief Baseband FFT plot timeout. */
void MainWindow::iqFftTimeout()
{
unsigned int fftsize;
unsigned int i;
double gain;
double pwr;
std::complex pt; /* a single FFT point used in calculations */
std::complex scaleFactor; /* normalizing factor (fftsize cast to complex) */
rx->get_iq_fft_data(d_fftData, fftsize);
if (fftsize == 0)
{
/* nothing to do, wait until next activation. */
return;
}
scaleFactor = std::complex((float)fftsize);
/** FIXME: move post processing to rx_fft_c **/
/* Normalize, calculcate power and shift the FFT */
for (i = 0; i < fftsize; i++)
{
/* normalize and shift */
if (i < fftsize/2)
{
pt = d_fftData[fftsize/2+i] / scaleFactor;
}
else
{
pt = d_fftData[i-fftsize/2] / scaleFactor;
}
pwr = pt.imag()*pt.imag() + pt.real()*pt.real();
/* calculate power in dBFS */
d_realFftData[i] = 10.0 * log10(pwr + 1.0e-20);
/* FFT averaging (aka. video filter) */
gain = d_fftAvg * (150.0+d_realFftData[i])/150.0;
//gain = 0.1;
d_iirFftData[i] = (1.0 - gain) * d_iirFftData[i] + gain * d_realFftData[i];
}
ui->plotter->setNewFttData(d_iirFftData, d_realFftData, fftsize);
}
/*! \brief Audio FFT plot timeout. */
void MainWindow::audioFftTimeout()
{
unsigned int fftsize;
unsigned int i;
std::complex pt; /* a single FFT point used in calculations */
std::complex scaleFactor; /* normalizing factor (fftsize cast to complex) */
if (!d_have_audio)
return;
rx->get_audio_fft_data(d_fftData, fftsize);
if (fftsize == 0)
{
/* nothing to do, wait until next activation. */
qDebug() << "No audio FFT data.";
return;
}
scaleFactor = std::complex((float)fftsize);
/** FIXME: move post processing to rx_fft_f **/
/* Normalize, calculcate power and shift the FFT */
for (i = 0; i < fftsize; i++)
{
/* normalize and shift */
if (i < fftsize/2)
{
pt = d_fftData[fftsize/2+i] / scaleFactor;
}
else
{
pt = d_fftData[i-fftsize/2] / scaleFactor;
}
/* calculate power in dBFS */
d_realFftData[i] = 10.0 * log10(pt.imag()*pt.imag() + pt.real()*pt.real() + 1.0e-20);
}
uiDockAudio->setNewFttData(d_realFftData, fftsize);
}
/*! \brief Start audio recorder.
* \param filename The file name into which audio should be recorded.
*/
void MainWindow::startAudioRec(const QString filename)
{
if (rx->start_audio_recording(filename.toStdString()))
{
ui->statusBar->showMessage(tr("Error starting audio recorder"));
/* reset state of record button */
uiDockAudio->setAudioRecButtonState(false);
}
else
{
ui->statusBar->showMessage(tr("Recording audio to %1").arg(filename));
}
}
/*! \brief Stop audio recorder. */
void MainWindow::stopAudioRec()
{
if (rx->stop_audio_recording())
{
/* okay, this one would be weird if it really happened */
ui->statusBar->showMessage(tr("Error stopping audio recorder"));
uiDockAudio->setAudioRecButtonState(true);
}
else
{
ui->statusBar->showMessage(tr("Audio recorder stopped"), 5000);
}
}
/*! \brief Start playback of audio file. */
void MainWindow::startAudioPlayback(const QString filename)
{
if (rx->start_audio_playback(filename.toStdString()))
{
ui->statusBar->showMessage(tr("Error trying to play %1").arg(filename));
/* reset state of record button */
uiDockAudio->setAudioPlayButtonState(false);
}
else
{
ui->statusBar->showMessage(tr("Playing %1").arg(filename));
}
}
/*! \brief Stop playback of audio file. */
void MainWindow::stopAudioPlayback()
{
if (rx->stop_audio_playback())
{
/* okay, this one would be weird if it really happened */
ui->statusBar->showMessage(tr("Error stopping audio playback"));
uiDockAudio->setAudioPlayButtonState(true);
}
else
{
ui->statusBar->showMessage(tr("Audio playback stopped"), 5000);
}
}
/*! \brief Start streaming audio over UDP. */
void MainWindow::startAudioStream(const QString udp_host, int udp_port)
{
rx->start_udp_streaming(udp_host.toStdString(), udp_port);
}
/*! \brief Stop streaming audio over UDP. */
void MainWindow::stopAudioStreaming()
{
rx->stop_udp_streaming();
}
/*! \brief Start/stop I/Q data playback.
* \param play True if playback is started, false if it is stopped.
* \param filename Full path of the I/Q data file.
*/
void MainWindow::toggleIqPlayback(bool play, const QString filename)
{
if (play)
{
/* starting playback */
if (rx->start_iq_playback(filename.toStdString(), 96000.0))
{
ui->statusBar->showMessage(tr("Error trying to play %1").arg(filename));
}
else
{
ui->statusBar->showMessage(tr("Playing %1").arg(filename));
/* disable REC button */
ui->actionIqRec->setEnabled(false);
}
}
else
{
/* stopping playback */
if (rx->stop_iq_playback())
{
/* okay, this one would be weird if it really happened */
ui->statusBar->showMessage(tr("Error stopping I/Q playback"));
}
else
{
ui->statusBar->showMessage(tr("I/Q playback stopped"), 5000);
}
/* enable REC button */
ui->actionIqRec->setEnabled(true);
}
}
/*! \brief FFT size has changed. */
void MainWindow::setIqFftSize(int size)
{
qDebug() << "Changing baseband FFT size to" << size;
rx->set_iq_fft_size(size);
}
/*! \brief Baseband FFT rate has changed. */
void MainWindow::setIqFftRate(int fps)
{
int interval;
if (fps == 0)
{
interval = 36e7; // 100 hours
ui->plotter->setRunningState(false);
}
else
{
interval = 1000 / fps;
if (iq_fft_timer->isActive())
ui->plotter->setRunningState(true);
}
if (interval > 9 && iq_fft_timer->isActive())
iq_fft_timer->setInterval(interval);
}
/*! \brief Vertical split between waterfall and pandapter changed.
* \param pct_pand The percentage of the waterfall.
*/
void MainWindow::setIqFftSplit(int pct_wf)
{
if ((pct_wf >= 10) && (pct_wf <= 100))
{
ui->plotter->setPercent2DScreen(pct_wf);
}
}
void MainWindow::setIqFftAvg(double avg)
{
if ((avg >= 0) && (avg <= 1.0))
d_fftAvg = avg;
}
/*! \brief Audio FFT rate has changed. */
void MainWindow::setAudioFftRate(int fps)
{
int interval = 1000 / fps;
if (interval < 10)
return;
if (audio_fft_timer->isActive())
audio_fft_timer->setInterval(interval);
}
/*! Set FFT plot color. */
void MainWindow::setFftColor(const QColor color)
{
ui->plotter->setFftPlotColor(color);
uiDockAudio->setFftColor(color);
}
/*! Enalbe/disable filling the aread below the FFT plot. */
void MainWindow::setFftFill(bool enable)
{
ui->plotter->setFftFill(enable);
uiDockAudio->setFftFill(enable);
}
void MainWindow::setFftPeakHold(bool enable)
{
ui->plotter->setPeakHold(enable);
}
void MainWindow::setPeakDetection(bool enabled)
{
ui->plotter->setPeakDetection(enabled ,2);
}
/*! \brief Force receiver reconfiguration.
*
* Aka. jerky dongle workaround.
*
* This function forces a receiver reconfiguration by sending a fake
* selectDemod() signal using the current demodulator selection.
*
* This function provides a workaround for the "jerky streaming" that has
* been experienced using some RTL-SDR dongles when DSP processing is
* started. The jerkyness disappears when trhe receiver is reconfigured
* by selecting a new demodulator.
*/
void MainWindow::forceRxReconf()
{
qDebug() << "Force RX reconf (jerky dongle workarond)...";
selectDemod(uiDockRxOpt->currentDemod());
}
/*! \brief Start/Stop DSP processing.
* \param checked Flag indicating whether DSP processing should be ON or OFF.
*
* This slot is executed when the actionDSP is toggled by the user. This can either be
* via the menu bar or the "power on" button in the main toolbar.
*/
void MainWindow::on_actionDSP_triggered(bool checked)
{
if (checked)
{
/* start receiver */
rx->start();
/* start GUI timers */
meter_timer->start(100);
if (uiDockFft->fftRate())
{
iq_fft_timer->start(1000/uiDockFft->fftRate());
ui->plotter->setRunningState(true);
}
else
{
iq_fft_timer->start(36e7); // 100 hours
ui->plotter->setRunningState(false);
}
audio_fft_timer->start(40);
/* update menu text and button tooltip */
ui->actionDSP->setToolTip(tr("Stop DSP processing"));
ui->actionDSP->setText(tr("Stop DSP"));
// reconfigure RX after 1s to counteract possible jerky streaming from rtl dongles
QTimer::singleShot(1000, this, SLOT(forceRxReconf()));
}
else
{
/* stop GUI timers */
meter_timer->stop();
iq_fft_timer->stop();
audio_fft_timer->stop();
/* stop receiver */
rx->stop();
/* update menu text and button tooltip */
ui->actionDSP->setToolTip(tr("Start DSP processing"));
ui->actionDSP->setText(tr("Start DSP"));
ui->plotter->setRunningState(false);
}
}
/*! \brief Action: I/O device configurator triggered.
*
* This slot is activated when the user selects "I/O Devices" in the
* menu. It activates the I/O configurator and if the user closes the
* configurator using the OK button, the new configuration is read and
* sent to the receiver.
*/
int MainWindow::on_actionIoConfig_triggered()
{
qDebug() << "Configure I/O devices.";
CIoConfig *ioconf = new CIoConfig(m_settings);
int confres = ioconf->exec();
if (confres == QDialog::Accepted)
{
if (ui->actionDSP->isChecked())
// suspend DSP while we reload settings
on_actionDSP_triggered(false);
storeSession();
loadConfig(m_settings->fileName(), false);
if (ui->actionDSP->isChecked())
// restsart DSP
on_actionDSP_triggered(true);
}
delete ioconf;
return confres;
}
/*! \brief Runc first time configurator. */
int MainWindow::firstTimeConfig()
{
qDebug() << __func__;
CIoConfig *ioconf = new CIoConfig(m_settings);
int confres = ioconf->exec();
if (confres == QDialog::Accepted)
loadConfig(m_settings->fileName(), false);
delete ioconf;
return confres;
}
/*! \brief Load configuration activated by user. */
void MainWindow::on_actionLoadSettings_triggered()
{
QString cfgfile = QFileDialog::getOpenFileName(this,
tr("Load settings"),
m_last_dir.isEmpty() ? m_cfg_dir : m_last_dir,
tr("Settings (*.conf)"));
qDebug() << "File to open:" << cfgfile;
if (cfgfile.isEmpty())
return;
if (!cfgfile.endsWith(".conf", Qt::CaseSensitive))
cfgfile.append(".conf");
loadConfig(cfgfile, cfgfile != m_settings->fileName());
// store last dir
QFileInfo fi(cfgfile);
if (m_cfg_dir != fi.absolutePath())
m_last_dir = fi.absolutePath();
}
/*! \brief Save configuration activated by user. */
void MainWindow::on_actionSaveSettings_triggered()
{
QString cfgfile = QFileDialog::getSaveFileName(this,
tr("Save settings"),
m_last_dir.isEmpty() ? m_cfg_dir : m_last_dir,
tr("Settings (*.conf)"));
qDebug() << "File to save:" << cfgfile;
if (cfgfile.isEmpty())
return;
if (!cfgfile.endsWith(".conf", Qt::CaseSensitive))
cfgfile.append(".conf");
storeSession();
saveConfig(cfgfile);
// store last dir
QFileInfo fi(cfgfile);
if (m_cfg_dir != fi.absolutePath())
m_last_dir = fi.absolutePath();
}
/*! \brief Toggle I/Q recording. */
void MainWindow::on_actionIqRec_triggered(bool checked)
{
Q_UNUSED(checked)
#if 0
if (checked)
{
/* generate file name using date, time, rf freq and BW */
int freq = (int)rx->get_rf_freq()/1000;
// FIXME: option to use local time
QString lastRec = QDateTime::currentDateTimeUtc().toString("gqrx-yyyyMMdd-hhmmss-%1-96.'bin'").arg(freq);
/* start recorder */
if (rx->start_iq_recording(lastRec.toStdString()))
{
/* reset action status */
ui->actionIqRec->toggle();
ui->statusBar->showMessage(tr("Error starting I/Q recoder"));
}
else
{
ui->statusBar->showMessage(tr("Recording I/Q data to: %1").arg(lastRec), 5000);
/* disable I/Q player */
uiDockIqPlay->setEnabled(false);
}
}
else
{
/* stop current recording */
if (rx->stop_iq_recording())
{
ui->statusBar->showMessage(tr("Error stopping I/Q recoder"));
}
else
{
ui->statusBar->showMessage(tr("I/Q data recoding stopped"), 5000);
}
/* enable I/Q player */
uiDockIqPlay->setEnabled(true);
}
#endif
}
/* CPlotter::NewDemodFreq() is emitted */
void MainWindow::on_plotter_newDemodFreq(qint64 freq, qint64 delta)
{
// set RX filter
rx->set_filter_offset((double) delta);
// update RF freq label and channel filter offset
uiDockRxOpt->setFilterOffset(delta);
ui->freqCtrl->setFrequency(freq);
}
/* CPlotter::NewfilterFreq() is emitted */
void MainWindow::on_plotter_newFilterFreq(int low, int high)
{
receiver::status retcode;
/* parameter correctness will be checked in receiver class */
retcode = rx->set_filter((double) low, (double) high, d_filter_shape);
if (retcode == receiver::STATUS_OK)
uiDockRxOpt->setFilterParam(low, high);
}
void MainWindow::on_plotter_newCenterFreq(qint64 f)
{
rx->set_rf_freq(f);
ui->freqCtrl->setFrequency(f);
}
/*! \brief Full screen button or menu item toggled. */
void MainWindow::on_actionFullScreen_triggered(bool checked)
{
if (checked)
{
ui->statusBar->hide();
showFullScreen();
}
else
{
ui->statusBar->show();
showNormal();
}
}
/*! \brief Remote control button (or menu item) toggled. */
void MainWindow::on_actionRemoteControl_triggered(bool checked)
{
if (checked)
remote->start_server();
else
remote->stop_server();
}
/*! \brief Remote control configuration button (or menu item) clicked. */
void MainWindow::on_actionRemoteConfig_triggered()
{
RemoteControlSettings *rcs = new RemoteControlSettings();
rcs->setPort(remote->getPort());
rcs->setHosts(remote->getHosts());
if (rcs->exec() == QDialog::Accepted)
{
remote->setPort(rcs->getPort());
remote->setHosts(rcs->getHosts());
}
delete rcs;
}
#define DATA_BUFFER_SIZE 48000
/*! \brief AFSK1200 decoder action triggered.
*
* This slot is called when the user activates the AFSK1200
* action. It will create an AFSK1200 decoder window and start
* and start pushing data from the receiver to it.
*/
void MainWindow::on_actionAFSK1200_triggered()
{
if (dec_afsk1200 != 0)
{
qDebug() << "AFSK1200 decoder already active.";
dec_afsk1200->raise();
}
else
{
qDebug() << "Starting AFSK1200 decoder.";
/* start sample sniffer */
if (rx->start_sniffer(22050, DATA_BUFFER_SIZE) == receiver::STATUS_OK)
{
dec_afsk1200 = new Afsk1200Win(this);
connect(dec_afsk1200, SIGNAL(windowClosed()), this, SLOT(afsk1200win_closed()));
dec_afsk1200->show();
dec_timer->start(100);
}
else
{
QMessageBox::warning(this, tr("Gqrx error"),
tr("Error starting sample sniffer.\n"
"Close all data decoders and try again."),
QMessageBox::Ok, QMessageBox::Ok);
}
}
}
/*! \brief Destroy AFSK1200 decoder window got closed.
*
* This slot is connected to the windowClosed() signal of the AFSK1200 decoder
* object. We need this to properly destroy the object, stop timeout and clean
* up whatever need to be cleaned up.
*/
void MainWindow::afsk1200win_closed()
{
/* stop cyclic processing */
dec_timer->stop();
rx->stop_sniffer();
/* delete decoder object */
delete dec_afsk1200;
dec_afsk1200 = 0;
}
/*! \brief Cyclic processing for acquiring samples from receiver and
* processing them with data decoders (see dec_* objects)
*/
void MainWindow::decoderTimeout()
{
float buffer[DATA_BUFFER_SIZE];
unsigned int num;
//qDebug() << "Process decoder";
rx->get_sniffer_data(&buffer[0], num);
if (dec_afsk1200)
{
dec_afsk1200->process_samples(&buffer[0], num);
}
/* else stop timeout and sniffer? */
}
/*! \brief Launch Gqrx google group website. */
void MainWindow::on_actionUserGroup_triggered()
{
bool res = QDesktopServices::openUrl(QUrl("https://groups.google.com/forum/#!forum/gqrx",
QUrl::TolerantMode));
if (!res)
{
QMessageBox::warning(this, tr("Error"),
tr("Failed to open website:\n"
"https://groups.google.com/forum/#!forum/gqrx"),
QMessageBox::Close);
}
}
/*! \brief Action: About Qthid
*
* This slot is called when the user activates the
* Help|About menu item (or Gqrx|About on Mac)
*/
void MainWindow::on_actionAbout_triggered()
{
QMessageBox::about(this, tr("About Gqrx"),
tr("This is Gqrx %1
"
"Copyright (C) 2011-2013 Alexandru Csete & contributors.
"
"Gqrx is a software defined radio receiver powered by "
"GNU Radio and the Qt toolkit. "
"
Gqrx uses the GrOsmoSDR "
"input source block and and works with any input device supported by it including:"
"
"
"You can download the latest version from the "
"Gqrx website."
"
"
""
"Gqrx is licensed under the GNU General Public License."
"
").arg(VERSION));
}
/*! \brief Action: About Qt
*
* This slot is called when the user activates the
* Help|About Qt menu item (or Gqrx|About Qt on Mac)
*/
void MainWindow::on_actionAboutQt_triggered()
{
QMessageBox::aboutQt(this, tr("About Qt"));
}
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/mainwindow.h 0000664 0000000 0000000 00000013631 12260363731 0022515 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2011-2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include "qtgui/dockrxopt.h"
#include "qtgui/dockaudio.h"
#include "qtgui/dockinputctl.h"
#include "qtgui/dockiqplayer.h"
#include "qtgui/dockfft.h"
#include "qtgui/afsk1200win.h"
#include "applications/gqrx/remote_control.h"
// see https://bugreports.qt-project.org/browse/QTBUG-22829
#ifndef Q_MOC_RUN
#include "applications/gqrx/receiver.h"
#endif
namespace Ui {
class MainWindow; /*! The main window UI */
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent = 0);
~MainWindow();
bool loadConfig(const QString cfgfile, bool check_crash);
bool saveConfig(const QString cfgfile);
void storeSession();
bool configOk; /*!< Main app uses this flag to know whether we should abort or continue. */
signals:
void configChanged(QSettings *settings); /*!< New configuration has been loaded. */
public slots:
void setNewFrequency(qint64 rx_freq);
private:
Ui::MainWindow *ui;
QPointer m_settings; /*!< Application wide settings. */
QString m_cfg_dir; /*!< Default config dir, e.g. XDG_CONFIG_HOME. */
QString m_last_dir;
qint64 d_lnb_lo; /* LNB LO in Hz. */
qint64 d_hw_freq;
enum receiver::filter_shape d_filter_shape;
std::complex* d_fftData;
double *d_realFftData; /** FIXME: use vector */
double *d_iirFftData; /** FIXME: use vector */
double *d_pwrFftData; /** FIXME: use vector */
//double *d_audioFttData;
double d_fftAvg; /*!< FFT averaging parameter set by user (not the true gain). */
bool d_have_audio; /*!< Whether we have audio (i.e. not with demod_off. */
/* dock widgets */
DockRxOpt *uiDockRxOpt;
DockAudio *uiDockAudio;
DockInputCtl *uiDockInputCtl;
//DockIqPlayer *uiDockIqPlay;
DockFft *uiDockFft;
/* data decoders */
Afsk1200Win *dec_afsk1200;
QTimer *dec_timer;
QTimer *meter_timer;
QTimer *iq_fft_timer;
QTimer *audio_fft_timer;
receiver *rx;
RemoteControl *remote;
private:
void updateFrequencyRange(bool ignore_limits);
void updateGainStages();
private slots:
/* rf */
void setLnbLo(double freq_mhz);
void setAntenna(const QString antenna);
/* baseband receiver */
void setFilterOffset(qint64 freq_hz);
void setGain(QString name, double gain);
void setAutoGain(bool enabled);
void setFreqCorr(int ppm);
void setIqSwap(bool reversed);
void setDcCancel(bool enabled);
void setIqBalance(bool enabled);
void setIgnoreLimits(bool ignore_limits);
void selectDemod(int index);
void setFmMaxdev(float max_dev);
void setFmEmph(double tau);
void setAmDcr(bool enabled);
void setAgcOn(bool agc_on);
void setAgcHang(bool use_hang);
void setAgcThreshold(int threshold);
void setAgcSlope(int factor);
void setAgcDecay(int msec);
void setAgcGain(int gain);
void setNoiseBlanker(int nbid, bool on, float threshold);
void setSqlLevel(double level_db);
double setSqlLevelAuto();
void setAudioGain(float gain);
/* audio recording and playback */
void startAudioRec(const QString filename);
void stopAudioRec();
void startAudioPlayback(const QString filename);
void stopAudioPlayback();
void startAudioStream(const QString udp_host, int udp_port);
void stopAudioStreaming();
void toggleIqPlayback(bool play, const QString filename);
/* FFT settings */
void setIqFftSize(int size);
void setIqFftRate(int fps);
void setIqFftSplit(int pct_wf);
void setIqFftAvg(double avg);
void setAudioFftRate(int fps);
void setFftColor(const QColor color);
void setFftFill(bool enable);
void setPeakDetection(bool enabled);
void setFftPeakHold(bool enable);
void on_plotter_newDemodFreq(qint64 freq, qint64 delta); /*! New demod freq (aka. filter offset). */
void on_plotter_newFilterFreq(int low, int high); /*! New filter width */
void on_plotter_newCenterFreq(qint64 f);
/* menu and toolbar actions */
void on_actionDSP_triggered(bool checked);
int on_actionIoConfig_triggered();
void on_actionLoadSettings_triggered();
void on_actionSaveSettings_triggered();
void on_actionIqRec_triggered(bool checked);
void on_actionFullScreen_triggered(bool checked);
void on_actionRemoteControl_triggered(bool checked);
void on_actionRemoteConfig_triggered();
void on_actionAFSK1200_triggered();
void on_actionUserGroup_triggered();
void on_actionAbout_triggered();
void on_actionAboutQt_triggered();
/* window close signals */
void afsk1200win_closed();
void forceRxReconf();
int firstTimeConfig();
/* cyclic processing */
void decoderTimeout();
void meterTimeout();
void iqFftTimeout();
void audioFftTimeout();
};
#endif // MAINWINDOW_H
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/mainwindow.ui 0000664 0000000 0000000 00000030272 12260363731 0022703 0 ustar 00root root 0000000 0000000
MainWindow
0
0
950
600
gqrx
:/icons/icons/scope.svg:/icons/icons/scope.svg
QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks
2
0
2
0
0
-
2
-
0
0
371
41
QFrame::StyledPanel
QFrame::Raised
-
0
0
171
41
QFrame::StyledPanel
QFrame::Raised
-
Qt::Horizontal
40
20
-
0
0
QFrame::StyledPanel
QFrame::Raised
Main toolbar
TopToolBarArea
false
true
Quit
Quit application
Ctrl+Q
About Gqrx
Information about Gqrx
About Qt
About the Qt toolkit
true
:/icons/icons/power-off.svg:/icons/icons/power-off.svg
Start DSP
Start DSP
Ctrl+D
AFSK1200 Decoder
Start AFSK1200 decoder
true
false
:/icons/icons/clock.svg:/icons/icons/clock.svg
Scheduler
Schedule recordings and other actions
true
false
:/icons/icons/record.svg:/icons/icons/record.svg
Record I/Q
Record the raw I/Q samples to a binary file (will be large)
Ctrl+R
true
:/icons/icons/flash.svg:/icons/icons/flash.svg
I/O Devices
Configure I/O devices
true
:/icons/icons/help.svg:/icons/icons/help.svg
Gqrx user group
Discussion group for Gqrx users
true
:/icons/icons/fullscreen.svg:/icons/icons/fullscreen.svg
Full screen
Toggle full screen mode
F11
:/icons/icons/folder.svg:/icons/icons/folder.svg
Load settings
Load previously stored configuration
Ctrl+L
:/icons/icons/floppy.svg:/icons/icons/floppy.svg
Save settings
Save current configuration
Ctrl+S
true
:/icons/icons/tangeo-network-idle.svg:/icons/icons/tangeo-network-idle.svg
&Remote control
Remote control via TCP
:/icons/icons/settings.svg:/icons/icons/settings.svg
Remote &control settings
Configure remote control settings
CFreqCtrl
QFrame
1
CPlotter
QFrame
1
CMeter
QFrame
1
actionQuit
triggered()
MainWindow
close()
-1
-1
450
257
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/receiver.cpp 0000664 0000000 0000000 00000073762 12260363731 0022513 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2011-2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "applications/gqrx/receiver.h"
#include "dsp/correct_iq_cc.h"
#include "dsp/rx_fft.h"
#include "receivers/nbrx.h"
#include "receivers/wfmrx.h"
#ifdef WITH_PULSEAUDIO //pafix
#include "pulseaudio/pa_sink.h"
#else
#include
#endif
/*! \brief Public contructor.
* \param input_device Input device specifier.
* \param audio_device Audio output device specifier,
* e.g. hw:0 when using ALSA or Portaudio.
*
* \todo Option to use UHD device instead of FCD.
*/
receiver::receiver(const std::string input_device, const std::string audio_device)
: d_running(false),
d_input_rate(96000.0),
d_audio_rate(48000),
d_rf_freq(144800000.0),
d_filter_offset(0.0),
d_recording_wav(false),
d_sniffer_active(false),
d_iq_rev(false),
d_dc_cancel(false),
d_iq_balance(false),
d_demod(RX_DEMOD_OFF)
{
tb = gr::make_top_block("gqrx");
if (input_device.empty())
{
// FIXME: other OS
src = osmosdr::source::make("file=/dev/random,freq=428e6,rate=96000,repeat=true,throttle=true");
}
else
{
input_devstr = input_device;
src = osmosdr::source::make(input_device);
}
rx = make_nbrx(d_input_rate, d_audio_rate);
lo = gr::analog::sig_source_c::make(d_input_rate, gr::analog::GR_SIN_WAVE, 0.0, 1.0);
mixer = gr::blocks::multiply_cc::make();
iq_swap = make_iq_swap_cc(false);
dc_corr = make_dc_corr_cc(d_input_rate, 1.0);
iq_fft = make_rx_fft_c(4096u, 0);
audio_fft = make_rx_fft_f(4096u);
audio_gain0 = gr::blocks::multiply_const_ff::make(0.1);
audio_gain1 = gr::blocks::multiply_const_ff::make(0.1);
audio_udp_sink = make_udp_sink_f();
#ifdef WITH_PULSEAUDIO //pafix
audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output");
#else
audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true);
#endif
output_devstr = audio_device;
/* wav sink and source is created when rec/play is started */
audio_null_sink0 = gr::blocks::null_sink::make(sizeof(float));
audio_null_sink1 = gr::blocks::null_sink::make(sizeof(float));
sniffer = make_sniffer_f();
/* sniffer_rr is created at each activation. */
set_demod(RX_DEMOD_NFM);
#ifndef QT_NO_DEBUG_OUTPUT
gr::prefs pref;
std::cout << "Using audio backend: "
<< pref.get_string("audio", "audio_module", "N/A")
<< std::endl;
#endif
}
/*! \brief Public destructor. */
receiver::~receiver()
{
tb->stop();
/* FIXME: delete blocks? */
}
/*! \brief Start the receiver. */
void receiver::start()
{
/* FIXME: Check that flow graph is not running */
if (!d_running)
{
#ifndef WITH_PULSEAUDIO
if(d_demod != RX_DEMOD_OFF)
set_output_device("");
#endif
tb->start();
d_running = true;
}
}
/*! \brief Stop the receiver. */
void receiver::stop()
{
if (d_running)
{
tb->stop();
tb->wait(); // If the graph is needed to run again, wait() must be called after stop
d_running = false;
}
}
/*! \brief Select new input device.
*
* \bug When using ALSA, program will crash if the new device
* is the same as the previously used device:
* audio_alsa_source[hw:1]: Device or resource busy
*/
void receiver::set_input_device(const std::string device)
{
if (device.empty())
return;
if (input_devstr.compare(device) == 0)
{
#ifndef QT_NO_DEBUG_OUTPUT
std::cout << "No change in input device:" << std::endl
<< " old: " << input_devstr << std::endl
<< " new: " << device << std::endl;
#endif
return;
}
input_devstr = device;
tb->lock();
tb->disconnect(src, 0, iq_swap, 0);
src.reset();
src = osmosdr::source::make(device);
tb->connect(src, 0, iq_swap, 0);
tb->unlock();
}
/*! \brief Select new audio output device. */
void receiver::set_output_device(const std::string device)
{
if (output_devstr.compare(device) == 0)
{
#ifndef QT_NO_DEBUG_OUTPUT
std::cout << "No change in output device:" << std::endl
<< " old: " << output_devstr << std::endl
<< " new: " << device << std::endl;
#endif
#ifndef GQRX_OS_MACX
// we can return on any platform but OS X becasue of
// https://github.com/csete/gqrx/issues/66
return;
#endif
}
output_devstr = device;
tb->lock();
tb->disconnect(audio_gain0, 0, audio_snk, 0);
tb->disconnect(audio_gain1, 0, audio_snk, 1);
audio_snk.reset();
#ifdef WITH_PULSEAUDIO
audio_snk = make_pa_sink(device, d_audio_rate);
#else
audio_snk = gr::audio::sink::make(d_audio_rate, device, true);
#endif
tb->connect(audio_gain0, 0, audio_snk, 0);
tb->connect(audio_gain1, 0, audio_snk, 1);
tb->unlock();
}
/*! \brief Get a list of available antenna connectors. */
std::vector receiver::get_antennas(void)
{
return src->get_antennas();
}
/*! \brief Select antenna conenctor. */
void receiver::set_antenna(const std::string &antenna)
{
src->set_antenna(antenna);
}
/*! \brief Set new input sample rate.
* \param rate The desired input rate
* \return The actual sample rate set.
*/
double receiver::set_input_rate(double rate)
{
// don't bother with sub-hertz changes
if (fabs(rate-d_input_rate) < 1.0)
{
#ifndef QT_NO_DEBUG_OUTPUT
std::cout << "No siginficant change in input sample rate" << std::endl;
#endif
}
else
{
tb->lock();
d_input_rate = src->set_sample_rate(rate);
dc_corr->set_sample_rate(d_input_rate);
rx->set_quad_rate(d_input_rate);
lo->set_sampling_freq(d_input_rate);
tb->unlock();
}
return d_input_rate;
}
/*! \brief Get current input sample rate. */
double receiver::get_input_rate()
{
return d_input_rate;
}
/*! \brief Set new analog bandwidth.
* \param bw The new bandwidth.
* \return The actual bandwidth.
*/
double receiver::set_analog_bandwidth(double bw)
{
return src->set_bandwidth(bw);
}
/*! \brief Get current analog bandwidth. */
double receiver::get_analog_bandwidth()
{
return src->get_bandwidth();
}
/*! \brief Set I/Q reversed. */
void receiver::set_iq_swap(bool reversed)
{
if (reversed == d_iq_rev)
return;
d_iq_rev = reversed;
iq_swap->set_enabled(d_iq_rev);
}
/*! \brief Get current I/Q reversed setting.
* \retval true I/Q swappign is enabled.
* \retval false I/Q swapping is disabled.
*/
bool receiver::get_iq_swap(void)
{
return d_iq_rev;
}
/*! \brief Enable/disable automatic DC removal in the I/Q stream.
* \param enable Whether DC removal should enabled or not.
*/
void receiver::set_dc_cancel(bool enable)
{
if (enable == d_dc_cancel)
return;
d_dc_cancel = enable;
// until we have a way to switch on/off
// inside the dc_corr_cc we do a reconf
rx_demod demod = d_demod;
d_demod = RX_DEMOD_OFF;
set_demod(demod);
}
/*! \brief Get auto DC cancel status.
* \retval true Automatic DC removal is enabled.
* \retval false Automatic DC removal is disabled.
*/
bool receiver::get_dc_cancel(void)
{
return d_dc_cancel;
}
/*! \brief Enable/disable automatic I/Q balance.
* \param enable Whether automatic I/Q balance should be enabled.
*/
void receiver::set_iq_balance(bool enable)
{
if (enable == d_iq_balance)
return;
d_iq_balance = enable;
src->set_iq_balance_mode(enable ? 2 : 0);
}
/*! \brief Get auto I/Q balance status.
* \retval true Automatic I/Q balance is enabled.
* \retval false Automatic I/Q balance is disabled.
*/
bool receiver::get_iq_balance(void)
{
return d_iq_balance;
}
/*! \brief Set RF frequency.
* \param freq_hz The desired frequency in Hz.
* \return RX_STATUS_ERROR if an error occurs, e.g. the frequency is out of range.
* \sa get_rf_freq()
*/
receiver::status receiver::set_rf_freq(double freq_hz)
{
d_rf_freq = freq_hz;
src->set_center_freq(d_rf_freq);
// FIXME: read back frequency?
return STATUS_OK;
}
/*! \brief Get RF frequency.
* \return The current RF frequency.
* \sa set_rf_freq()
*/
double receiver::get_rf_freq()
{
d_rf_freq = src->get_center_freq();
return d_rf_freq;
}
/*! \brief Get the RF frequency range of the current input device.
* \param start The lower limit of the range in Hz.
* \param stop The upper limit of the range in Hz.
* \param step The frequency step in Hz.
* \returns STATUS_OK if the range could be retrieved, STATUS_ERROR if an error has occurred.
*/
receiver::status receiver::get_rf_range(double *start, double *stop, double *step)
{
osmosdr::freq_range_t range;
range = src->get_freq_range();
// currently range is empty for all but E4000
if (!range.empty())
{
if (range.start() < range.stop())
{
*start = range.start();
*stop = range.stop();
*step = range.step(); /** FIXME: got 0 for rtl-sdr? **/
return STATUS_OK;
}
}
return STATUS_ERROR;
}
/*! \brief Get the names of available gain stages. */
std::vector receiver::get_gain_names()
{
return src->get_gain_names();
}
/*! \brief Get gain range for a specific stage.
* \param[in] name The name of the gain stage.
* \param[out] start Lower limit for this gain setting.
* \param[out] stop Upper limit for this gain setting.
* \param[out] step The resolution for this gain setting.
*
* This function retunrs the range for the requested gain stage.
*/
receiver::status receiver::get_gain_range(std::string &name, double *start, double *stop, double *step)
{
osmosdr::gain_range_t range;
range = src->get_gain_range(name);
*start = range.start();
*stop = range.stop();
*step = range.step();
return STATUS_OK;
}
receiver::status receiver::set_gain(std::string name, double value)
{
src->set_gain(value, name);
return STATUS_OK;
}
double receiver::get_gain(std::string name)
{
return src->get_gain(name);
}
/*! \brief Set RF gain.
* \param gain_rel The desired relative gain between 0.0 and 1.0 (use -1 for AGC where supported).
* \return RX_STATUS_ERROR if an error occurs, e.g. the gain is out of valid range.
*/
receiver::status receiver::set_auto_gain(bool automatic)
{
src->set_gain_mode(automatic);
return STATUS_OK;
}
/*! \brief Set filter offset.
* \param offset_hz The desired filter offset in Hz.
* \return RX_STATUS_ERROR if the tuning offset is out of range.
*
* This method sets a new tuning offset for the receiver. The tuning offset is used
* to tune within the passband, i.e. select a specific channel within the received
* spectrum.
*
* The valid range for the tuning is +/- 0.5 * the bandwidth although this is just a
* logical limit.
*
* \sa get_filter_offset()
*/
receiver::status receiver::set_filter_offset(double offset_hz)
{
d_filter_offset = offset_hz;
lo->set_frequency(-d_filter_offset);
return STATUS_OK;
}
/*! \brief Get filterm offset.
* \return The current filter offset.
* \sa set_filter_offset()
*/
double receiver::get_filter_offset()
{
return d_filter_offset;
}
receiver::status receiver::set_filter(double low, double high, filter_shape shape)
{
double trans_width;
if ((low >= high) || (abs(high-low) < RX_FILTER_MIN_WIDTH))
return STATUS_ERROR;
switch (shape) {
case FILTER_SHAPE_SOFT:
trans_width = abs(high-low)*0.2;
break;
case FILTER_SHAPE_SHARP:
trans_width = abs(high-low)*0.01;
break;
case FILTER_SHAPE_NORMAL:
default:
trans_width = abs(high-low)*0.1;
break;
}
rx->set_filter(low, high, trans_width);
return STATUS_OK;
}
/**
receiver::status receiver::set_filter_low(double freq_hz)
{
return STATUS_OK;
}
receiver::status receiver::set_filter_high(double freq_hz)
{
return STATUS_OK;
}
receiver::status receiver::set_filter_shape(filter_shape shape)
{
return STATUS_OK;
}
**/
receiver::status receiver::set_freq_corr(int ppm)
{
src->set_freq_corr(ppm);
return STATUS_OK;
}
/*! \brief Get current signal power.
* \param dbfs Whether to use dbfs or absolute power.
* \return The current signal power.
*
* This method returns the current signal power detected by the receiver. The detector
* is located after the band pass filter. The full scale is 1.0
*/
float receiver::get_signal_pwr(bool dbfs)
{
return rx->get_signal_level(dbfs);
}
/*! \brief Set new FFT size. */
void receiver::set_iq_fft_size(int newsize)
{
iq_fft->set_fft_size(newsize);
}
/*! \brief Get latest baseband FFT data. */
void receiver::get_iq_fft_data(std::complex* fftPoints, unsigned int &fftsize)
{
iq_fft->get_fft_data(fftPoints, fftsize);
}
/*! \brief Get latest audio FFT data. */
void receiver::get_audio_fft_data(std::complex* fftPoints, unsigned int &fftsize)
{
audio_fft->get_fft_data(fftPoints, fftsize);
}
receiver::status receiver::set_nb_on(int nbid, bool on)
{
if (rx->has_nb())
rx->set_nb_on(nbid, on);
return STATUS_OK; // FIXME
}
receiver::status receiver::set_nb_threshold(int nbid, float threshold)
{
if (rx->has_nb())
rx->set_nb_threshold(nbid, threshold);
return STATUS_OK; // FIXME
}
/*! \brief Set squelch level.
* \param level_db The new level in dBFS.
*/
receiver::status receiver::set_sql_level(double level_db)
{
if (rx->has_sql())
rx->set_sql_level(level_db);
return STATUS_OK; // FIXME
}
/*! \brief Set squelch alpha */
receiver::status receiver::set_sql_alpha(double alpha)
{
if (rx->has_sql())
rx->set_sql_alpha(alpha);
return STATUS_OK; // FIXME
}
/*! \brief Enable/disable receiver AGC.
*
* When AGC is disabled a fixed manual gain is used, see set_agc_manual_gain().
*/
receiver::status receiver::set_agc_on(bool agc_on)
{
if (rx->has_agc())
rx->set_agc_on(agc_on);
return STATUS_OK; // FIXME
}
/*! \brief Enable/disable AGC hang. */
receiver::status receiver::set_agc_hang(bool use_hang)
{
if (rx->has_agc())
rx->set_agc_hang(use_hang);
return STATUS_OK; // FIXME
}
/*! \brief Set AGC threshold. */
receiver::status receiver::set_agc_threshold(int threshold)
{
if (rx->has_agc())
rx->set_agc_threshold(threshold);
return STATUS_OK; // FIXME
}
/*! \brief Set AGC slope. */
receiver::status receiver::set_agc_slope(int slope)
{
if (rx->has_agc())
rx->set_agc_slope(slope);
return STATUS_OK; // FIXME
}
/*! \brief Set AGC decay time. */
receiver::status receiver::set_agc_decay(int decay_ms)
{
if (rx->has_agc())
rx->set_agc_decay(decay_ms);
return STATUS_OK; // FIXME
}
/*! \brief Set fixed gain used when AGC is OFF. */
receiver::status receiver::set_agc_manual_gain(int gain)
{
if (rx->has_agc())
rx->set_agc_manual_gain(gain);
return STATUS_OK; // FIXME
}
receiver::status receiver::set_demod(rx_demod demod)
{
bool needs_restart = d_running;
bool wide_fm = (d_demod == RX_DEMOD_WFM_M) || (d_demod == RX_DEMOD_WFM_S);
status ret = STATUS_OK;
// Allow reconf using same demod to provide a workaround
// for the "jerky streaming" we may experience with rtl
// dongles (the jerkyness disappears when we run this function)
//if (demod == d_demod)
// return ret;
if (d_running)
stop();
switch (demod)
{
case RX_DEMOD_OFF:
tb->disconnect_all();
connect_all(RX_CHAIN_NONE);
break;
case RX_DEMOD_NONE:
if ((d_demod == RX_DEMOD_OFF) || wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_NBRX);
}
rx->set_demod(nbrx::NBRX_DEMOD_NONE);
break;
case RX_DEMOD_AM:
if ((d_demod == RX_DEMOD_OFF) || wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_NBRX);
}
rx->set_demod(nbrx::NBRX_DEMOD_AM);
break;
case RX_DEMOD_NFM:
if ((d_demod == RX_DEMOD_OFF) || wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_NBRX);
}
rx->set_demod(nbrx::NBRX_DEMOD_FM);
break;
case RX_DEMOD_WFM_M:
if (!wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_WFMRX);
}
rx->set_demod(wfmrx::WFMRX_DEMOD_MONO);
break;
case RX_DEMOD_WFM_S:
if (!wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_WFMRX);
}
rx->set_demod(wfmrx::WFMRX_DEMOD_STEREO);
break;
case RX_DEMOD_SSB:
if ((d_demod == RX_DEMOD_OFF) || wide_fm)
{
tb->disconnect_all();
connect_all(RX_CHAIN_NBRX);
}
rx->set_demod(nbrx::NBRX_DEMOD_SSB);
break;
default:
ret = STATUS_ERROR;
break;
}
d_demod = demod;
if (needs_restart)
start();
return ret;
}
/*! \brief Set maximum deviation of the FM demodulator.
* \param maxdev_hz The new maximum deviation in Hz.
*/
receiver::status receiver::set_fm_maxdev(float maxdev_hz)
{
if (rx->has_fm())
rx->set_fm_maxdev(maxdev_hz);
return STATUS_OK;
}
receiver::status receiver::set_fm_deemph(double tau)
{
if (rx->has_fm())
rx->set_fm_deemph(tau);
return STATUS_OK;
}
receiver::status receiver::set_am_dcr(bool enabled)
{
if (rx->has_am())
rx->set_am_dcr(enabled);
return STATUS_OK;
}
receiver::status receiver::set_af_gain(float gain_db)
{
float k;
/* convert dB to factor */
k = pow(10.0, gain_db / 20.0);
//std::cout << "G:" << gain_db << "dB / K:" << k << std::endl;
audio_gain0->set_k(k);
audio_gain1->set_k(k);
return STATUS_OK;
}
/*! \brief Start WAV file recorder.
* \param filename The filename where to record.
*
* A new recorder object is created every time we start recording and deleted every time
* we stop recording. The idea of creating one object and starting/stopping using different
* file names does not work with WAV files (the initial /tmp/gqrx.wav will not be stopped
* because the wav file can not be empty). See https://github.com/csete/gqrx/issues/36
*/
receiver::status receiver::start_audio_recording(const std::string filename)
{
if (d_recording_wav)
{
/* error - we are already recording */
std::cout << "ERROR: Can not start audio recorder (already recording)" << std::endl;
return STATUS_ERROR;
}
if (!d_running)
{
/* receiver is not running */
std::cout << "Can not start audio recorder (receiver not running)" << std::endl;
return STATUS_ERROR;
}
// not strictly necessary to lock but I think it is safer
tb->lock();
wav_sink = gr::blocks::wavfile_sink::make(filename.c_str(),
2,
(unsigned int) d_audio_rate,
16);
tb->connect(rx, 0, wav_sink, 0);
tb->connect(rx, 1, wav_sink, 1);
tb->unlock();
d_recording_wav = true;
std::cout << "Recording audio to " << filename << std::endl;
return STATUS_OK;
}
/*! \brief Stop WAV file recorder. */
receiver::status receiver::stop_audio_recording()
{
if (!d_recording_wav) {
/* error: we are not recording */
std::cout << "ERROR: Can not stop audio recorder (not recording)" << std::endl;
return STATUS_ERROR;
}
if (!d_running)
{
/* receiver is not running */
std::cout << "Can not start audio recorder (receiver not running)" << std::endl;
return STATUS_ERROR;
}
// not strictly necessary to lock but I think it is safer
tb->lock();
wav_sink->close();
tb->disconnect(rx, 0, wav_sink, 0);
tb->disconnect(rx, 1, wav_sink, 1);
wav_sink.reset(); /** FIXME **/
tb->unlock();
d_recording_wav = false;
std::cout << "Audio recorder stopped" << std::endl;
return STATUS_OK;
}
/*! \brief Start audio playback. */
receiver::status receiver::start_audio_playback(const std::string filename)
{
if (!d_running)
{
/* receiver is not running */
std::cout << "Can not start audio playback (receiver not running)" << std::endl;
return STATUS_ERROR;
}
try {
// output ports set automatically from file
wav_src = gr::blocks::wavfile_source::make(filename.c_str(), false);
}
catch (std::runtime_error &e) {
std::cout << "Error loading " << filename << ": " << e.what() << std::endl;
return STATUS_ERROR;
}
/** FIXME: We can only handle native rate (should maybe use the audio_rr)? */
unsigned int audio_rate = (unsigned int) d_audio_rate;
if (wav_src->sample_rate() != audio_rate)
{
std::cout << "BUG: Can not handle sample rate " << wav_src->sample_rate() << std::endl;
wav_src.reset();
return STATUS_ERROR;
}
/** FIXME: We can only handle stereo files */
if (wav_src->channels() != 2)
{
std::cout << "BUG: Can not handle other than 2 channels. File has " << wav_src->channels() << std::endl;
wav_src.reset();
return STATUS_ERROR;
}
stop();
/* route demodulator output to null sink */
tb->disconnect(rx, 0, audio_gain0, 0);
tb->disconnect(rx, 1, audio_gain1, 0);
tb->disconnect(rx, 0, audio_fft, 0);
tb->disconnect(rx, 0, audio_udp_sink, 0);
tb->connect(rx, 0, audio_null_sink0, 0); /** FIXME: other channel? */
tb->connect(rx, 1, audio_null_sink1, 0); /** FIXME: other channel? */
tb->connect(wav_src, 0, audio_gain0, 0);
tb->connect(wav_src, 1, audio_gain1, 0);
tb->connect(wav_src, 0, audio_fft, 0);
tb->connect(wav_src, 0, audio_udp_sink, 0);
start();
std::cout << "Playing audio from " << filename << std::endl;
return STATUS_OK;
}
/*! \brief Stop audio playback. */
receiver::status receiver::stop_audio_playback()
{
/* disconnect wav source and reconnect receiver */
stop();
tb->disconnect(wav_src, 0, audio_gain0, 0);
tb->disconnect(wav_src, 1, audio_gain1, 0);
tb->disconnect(wav_src, 0, audio_fft, 0);
tb->disconnect(wav_src, 0, audio_udp_sink, 0);
tb->disconnect(rx, 0, audio_null_sink0, 0);
tb->disconnect(rx, 1, audio_null_sink1, 0);
tb->connect(rx, 0, audio_gain0, 0);
tb->connect(rx, 1, audio_gain1, 0);
tb->connect(rx, 0, audio_fft, 0); /** FIXME: other channel? */
tb->connect(rx, 0, audio_udp_sink, 0);
start();
/* delete wav_src since we can not change file name */
wav_src.reset();
return STATUS_OK;
}
/*! \brief Start UDP streaming of audio. */
receiver::status receiver::start_udp_streaming(const std::string host, int port)
{
audio_udp_sink->start_streaming(host, port);
return STATUS_OK;
}
/*! \brief Stop UDP streaming of audio. */
receiver::status receiver::stop_udp_streaming()
{
audio_udp_sink->stop_streaming();
return STATUS_OK;
}
/*! \brief Start I/Q data recorder.
* \param filename The filename where to record.
*/
receiver::status receiver::start_iq_recording(const std::string filename)
{
(void) filename;
#if 0
if (d_recording_iq) {
/* error - we are already recording */
return STATUS_ERROR;
}
/* iq_sink was created in the constructor */
if (iq_sink) {
/* not strictly necessary to lock but I think it is safer */
tb->lock();
iq_sink->open(filename.c_str());
tb->unlock();
d_recording_iq = true;
}
else {
std::cout << "BUG: I/Q file sink does not exist" << std::endl;
}
#endif
return STATUS_OK;
}
/*! \brief Stop I/Q data recorder. */
receiver::status receiver::stop_iq_recording()
{
#if 0
if (!d_recording_iq) {
/* error: we are not recording */
return STATUS_ERROR;
}
tb->lock();
iq_sink->close();
tb->unlock();
d_recording_iq = false;
#endif
return STATUS_OK;
}
/*! \brief Start playback of recorded I/Q data file.
* \param filename The file to play from. Must be raw file containing gr_complex samples.
* \param samprate The sample rate (currently fixed at 96ksps)
*/
receiver::status receiver::start_iq_playback(const std::string filename, float samprate)
{
(void) filename;
(void) samprate;
#if 0
if (samprate != d_bandwidth) {
return STATUS_ERROR;
}
try {
iq_src = gr_make_file_source(sizeof(gr_complex), filename.c_str(), false);
}
catch (std::runtime_error &e) {
std::cout << "Error loading " << filename << ": " << e.what() << std::endl;
return STATUS_ERROR;
}
tb->lock();
/* disconenct hardware source */
tb->disconnect(src, 0, nb, 0);
tb->disconnect(src, 0, iq_sink, 0);
/* connect I/Q source via throttle block */
tb->connect(iq_src, 0, nb, 0);
tb->connect(iq_src, 0, iq_sink, 0);
tb->unlock();
#endif
return STATUS_OK;
}
/*! \brief Stop I/Q data file playback.
* \return STATUS_OK
*
* This method will stop the I/Q data playback, disconnect the file source and throttle
* blocks, and reconnect the hardware source.
*
* FIXME: will probably crash if we try to stop playback that is not running.
*/
receiver::status receiver::stop_iq_playback()
{
#if 0
tb->lock();
/* disconnect I/Q source and throttle block */
tb->disconnect(iq_src, 0, nb, 0);
tb->disconnect(iq_src, 0, iq_sink, 0);
/* reconenct hardware source */
tb->connect(src, 0, nb, 0);
tb->connect(src, 0, iq_sink, 0);
tb->unlock();
/* delete iq_src since we can not reuse for other files */
iq_src.reset();
#endif
return STATUS_OK;
}
/*! \brief Start data sniffer.
* \param buffsize The buffer that should be used in the sniffer.
* \return STATUS_OK if the sniffer was started, STATUS_ERROR if the sniffer is already in use.
*/
receiver::status receiver::start_sniffer(unsigned int samprate, int buffsize)
{
if (d_sniffer_active) {
/* sniffer already in use */
return STATUS_ERROR;
}
sniffer->set_buffer_size(buffsize);
sniffer_rr = make_resampler_ff((float)samprate/(float)d_audio_rate);
tb->lock();
tb->connect(rx, 0, sniffer_rr, 0);
tb->connect(sniffer_rr, 0, sniffer, 0);
tb->unlock();
d_sniffer_active = true;
return STATUS_OK;
}
/*! \brief Stop data sniffer.
* \return STATUS_ERROR i the sniffer is not currently active.
*/
receiver::status receiver::stop_sniffer()
{
if (!d_sniffer_active) {
return STATUS_ERROR;
}
tb->lock();
tb->disconnect(rx, 0, sniffer_rr, 0);
tb->disconnect(sniffer_rr, 0, sniffer, 0);
tb->unlock();
d_sniffer_active = false;
/* delete resampler */
sniffer_rr.reset();
return STATUS_OK;
}
/*! \brief Get sniffer data. */
void receiver::get_sniffer_data(float * outbuff, unsigned int &num)
{
sniffer->get_samples(outbuff, num);
}
/*! \brief Convenience function to connect all blocks. */
void receiver::connect_all(rx_chain type)
{
switch (type)
{
case RX_CHAIN_NONE:
tb->connect(src, 0, iq_swap, 0);
if (d_dc_cancel)
{
tb->connect(iq_swap, 0, dc_corr, 0);
tb->connect(dc_corr, 0, iq_fft, 0);
}
else
{
tb->connect(iq_swap, 0, iq_fft, 0);
}
break;
case RX_CHAIN_NBRX:
if (rx->name() != "NBRX")
{
rx.reset();
rx = make_nbrx(d_input_rate, d_audio_rate);
}
tb->connect(src, 0, iq_swap, 0);
if (d_dc_cancel)
{
tb->connect(iq_swap, 0, dc_corr, 0);
tb->connect(dc_corr, 0, iq_fft, 0);
tb->connect(dc_corr, 0, mixer, 0);
}
else
{
tb->connect(iq_swap, 0, iq_fft, 0);
tb->connect(iq_swap, 0, mixer, 0);
}
tb->connect(lo, 0, mixer, 1);
tb->connect(mixer, 0, rx, 0);
tb->connect(rx, 0, audio_fft, 0);
tb->connect(rx, 0, audio_udp_sink, 0);
tb->connect(rx, 0, audio_gain0, 0);
tb->connect(rx, 1, audio_gain1, 0);
tb->connect(audio_gain0, 0, audio_snk, 0);
tb->connect(audio_gain1, 0, audio_snk, 1);
break;
case RX_CHAIN_WFMRX:
if (rx->name() != "WFMRX")
{
rx.reset();
rx = make_wfmrx(d_input_rate, d_audio_rate);
}
tb->connect(src, 0, iq_swap, 0);
if (d_dc_cancel)
{
tb->connect(iq_swap, 0, dc_corr, 0);
tb->connect(dc_corr, 0, iq_fft, 0);
tb->connect(dc_corr, 0, mixer, 0);
}
else
{
tb->connect(iq_swap, 0, iq_fft, 0);
tb->connect(iq_swap, 0, mixer, 0);
}
tb->connect(lo, 0, mixer, 1);
tb->connect(mixer, 0, rx, 0);
tb->connect(rx, 0, audio_fft, 0);
tb->connect(rx, 0, audio_udp_sink, 0);
tb->connect(rx, 0, audio_gain0, 0);
tb->connect(rx, 1, audio_gain1, 0);
tb->connect(audio_gain0, 0, audio_snk, 0);
tb->connect(audio_gain1, 0, audio_snk, 1);
break;
default:
break;
}
// re-connect audio data sniffer if it is activated
if (d_sniffer_active)
{
tb->connect(rx, 0, sniffer_rr, 0);
tb->connect(sniffer_rr, 0, sniffer, 0);
}
}
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/receiver.h 0000664 0000000 0000000 00000021744 12260363731 0022151 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2011-2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef RECEIVER_H
#define RECEIVER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "dsp/correct_iq_cc.h"
#include "dsp/rx_noise_blanker_cc.h"
#include "dsp/rx_filter.h"
#include "dsp/rx_meter.h"
#include "dsp/rx_agc_xx.h"
#include "dsp/rx_demod_fm.h"
#include "dsp/rx_demod_am.h"
#include "dsp/rx_fft.h"
#include "dsp/sniffer_f.h"
#include "dsp/resampler_xx.h"
#include "interfaces/udp_sink_f.h"
#include "receivers/receiver_base.h"
#ifdef WITH_PULSEAUDIO
#include
#else
#include
#endif
/*! \defgroup DSP Digital signal processing library based on GNU Radio */
/*! \brief Top-level receiver class.
* \ingroup DSP
*
* This class encapsulates the GNU Radio flow graph for the receiver.
* Front-ends should only control the receiver through the interface provided
* by this class.
*
*/
class receiver
{
public:
/*! \brief Flag used to indicate success or failure of an operation, usually a set_something(). */
enum status {
STATUS_OK = 0, /*!< Operation was successful. */
STATUS_ERROR = 1 /*!< There was an error. */
};
/*! \brief Available demodulators. */
enum rx_demod {
RX_DEMOD_OFF = 0, /*!< No receiver. */
RX_DEMOD_NONE = 1, /*!< No demod. Raw I/Q to audio. */
RX_DEMOD_AM = 2, /*!< Amplitude modulation. */
RX_DEMOD_NFM = 3, /*!< Frequency modulation. */
RX_DEMOD_WFM_M = 4, /*!< Frequency modulation (wide, mono). */
RX_DEMOD_WFM_S = 5, /*!< Frequency modulation (wide, stereo). */
RX_DEMOD_SSB = 6 /*!< Single Side Band. */
};
/*! \brief Supported receiver types. */
enum rx_chain {
RX_CHAIN_NONE = 0, /*!< No receiver, just spectrum analyzer. */
RX_CHAIN_NBRX = 1, /*!< Narrow band receiver (AM, FM, SSB). */
RX_CHAIN_WFMRX = 2 /*!< Wide band FM receiver (for broadcast). */
};
/*! \brief Filter shape (convenience wrappers for "transition width"). */
enum filter_shape {
FILTER_SHAPE_SOFT = 0, /*!< Soft: Transition band is TBD of width. */
FILTER_SHAPE_NORMAL = 1, /*!< Normal: Transition band is TBD of width. */
FILTER_SHAPE_SHARP = 2 /*!< Sharp: Transition band is TBD of width. */
};
receiver(const std::string input_device="", const std::string audio_device="");
~receiver();
void start();
void stop();
void set_input_device(const std::string device);
void set_output_device(const std::string device);
std::vector get_antennas(void);
void set_antenna(const std::string &antenna);
double set_input_rate(double rate);
double get_input_rate();
double set_analog_bandwidth(double bw);
double get_analog_bandwidth();
void set_iq_swap(bool reversed);
bool get_iq_swap(void);
void set_dc_cancel(bool enable);
bool get_dc_cancel(void);
void set_iq_balance(bool enable);
bool get_iq_balance(void);
status set_rf_freq(double freq_hz);
double get_rf_freq();
status get_rf_range(double *start, double *stop, double *step);
std::vector get_gain_names();
status get_gain_range(std::string &name, double *start, double *stop, double *step);
status set_auto_gain(bool automatic);
status set_gain(std::string name, double value);
double get_gain(std::string name);
status set_filter_offset(double offset_hz);
double get_filter_offset();
status set_filter(double low, double high, filter_shape shape);
//status set_filter_low(double freq_hz);
//status set_filter_high(double freq_hz);
//status set_filter_shape(filter_shape shape);
status set_freq_corr(int ppm);
float get_signal_pwr(bool dbfs);
void set_iq_fft_size(int newsize);
void get_iq_fft_data(std::complex* fftPoints, unsigned int &fftsize);
void get_audio_fft_data(std::complex* fftPoints, unsigned int &fftsize);
/* Noise blanker */
status set_nb_on(int nbid, bool on);
status set_nb_threshold(int nbid, float threshold);
/* Squelch parameter */
status set_sql_level(double level_db);
status set_sql_alpha(double alpha);
/* AGC */
status set_agc_on(bool agc_on);
status set_agc_hang(bool use_hang);
status set_agc_threshold(int threshold);
status set_agc_slope(int slope);
status set_agc_decay(int decay_ms);
status set_agc_manual_gain(int gain);
status set_demod(rx_demod demod);
/* FM parameters */
status set_fm_maxdev(float maxdev_hz);
status set_fm_deemph(double tau);
/* AM parameters */
status set_am_dcr(bool enabled);
/* Audio parameters */
status set_af_gain(float gain_db);
status start_audio_recording(const std::string filename);
status stop_audio_recording();
status start_audio_playback(const std::string filename);
status stop_audio_playback();
status start_udp_streaming(const std::string host, int port);
status stop_udp_streaming();
/* I/Q recording and playback */
status start_iq_recording(const std::string filename);
status stop_iq_recording();
status start_iq_playback(const std::string filename, float samprate);
status stop_iq_playback();
/* sample sniffer */
status start_sniffer(unsigned int samplrate, int buffsize);
status stop_sniffer();
void get_sniffer_data(float * outbuff, unsigned int &num);
private:
void connect_all(rx_chain type);
private:
bool d_running; /*!< Whether receiver is running or not. */
double d_input_rate; /*!< Input sample rate. */
double d_audio_rate; /*!< Audio output rate. */
double d_rf_freq; /*!< Current RF frequency. */
double d_filter_offset; /*!< Current filter offset (tune within passband). */
bool d_recording_wav; /*!< Whether we are recording WAV file. */
bool d_sniffer_active; /*!< Only one data decoder allowed. */
bool d_iq_rev; /*!< Whether I/Q is reversed or not. */
bool d_dc_cancel; /*!< Enable automatic DC removal. */
bool d_iq_balance; /*!< Enable automatic IQ balance. */
std::string input_devstr; /*!< Current input device string. */
std::string output_devstr; /*!< Current output device string. */
rx_demod d_demod; /*!< Current demodulator. */
gr::top_block_sptr tb; /*!< The GNU Radio top block. */
osmosdr::source::sptr src; /*!< Real time I/Q source. */
//rx_source_base::sptr src; /*!< Real time I/Q source. */
receiver_base_cf_sptr rx; /*!< receiver. */
dc_corr_cc_sptr dc_corr; /*!< DC corrector block. */
iq_swap_cc_sptr iq_swap; /*!< I/Q swapping block. */
rx_fft_c_sptr iq_fft; /*!< Baseband FFT block. */
rx_fft_f_sptr audio_fft; /*!< Audio FFT block. */
gr::analog::sig_source_c::sptr lo; /*!< oscillator used for tuning. */
gr::blocks::multiply_cc::sptr mixer;
gr::blocks::multiply_const_ff::sptr audio_gain0; /*!< Audio gain block. */
gr::blocks::multiply_const_ff::sptr audio_gain1; /*!< Audio gain block. */
gr::blocks::wavfile_sink::sptr wav_sink; /*!< WAV file sink for recording. */
gr::blocks::wavfile_source::sptr wav_src; /*!< WAV file source for playback. */
gr::blocks::null_sink::sptr audio_null_sink0; /*!< Audio null sink used during playback. */
gr::blocks::null_sink::sptr audio_null_sink1; /*!< Audio null sink used during playback. */
udp_sink_f_sptr audio_udp_sink; /*!< UDP sink to stream audio over the network. */
sniffer_f_sptr sniffer; /*!< Sample sniffer for data decoders. */
resampler_ff_sptr sniffer_rr; /*!< Sniffer resampler. */
#ifdef WITH_PULSEAUDIO
pa_sink_sptr audio_snk; /*!< Pulse audio sink. */
#else
gr::audio::sink::sptr audio_snk; /*!< gr audio sink */
#endif
};
#endif // RECEIVER_H
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/remote_control.cpp 0000664 0000000 0000000 00000014433 12260363731 0023730 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include
#include "remote_control.h"
RemoteControl::RemoteControl(QObject *parent) :
QObject(parent)
{
rc_freq = 0;
rc_filter_offset = 0;
bw_half = 740e3;
rc_port = 7356;
rc_allowed_hosts.append("127.0.0.1");
rc_socket = 0;
connect(&rc_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}
RemoteControl::~RemoteControl()
{
stop_server();
}
/*! \brief Start the server. */
void RemoteControl::start_server()
{
rc_server.listen(QHostAddress::Any, rc_port);
}
/*! \brief Stop the server. */
void RemoteControl::stop_server()
{
if (rc_socket != 0)
rc_socket->close();
if (rc_server.isListening())
rc_server.close();
}
/*! \brief Read settings. */
void RemoteControl::readSettings(QSettings *settings)
{
bool conv_ok;
rc_freq = settings->value("input/frequency", 144500000).toLongLong(&conv_ok);
rc_filter_offset = settings->value("receiver/offset", 0).toInt(&conv_ok);
// Get port number; restart server if running
rc_port = settings->value("remote_control/port", 7356).toInt(&conv_ok);
if (rc_server.isListening())
{
rc_server.close();
rc_server.listen(QHostAddress::Any, rc_port);
}
// get list of allowed hosts
if (settings->contains("remote_control/allowed_hosts"))
rc_allowed_hosts = settings->value("remote_control/allowed_hosts").toStringList();
}
void RemoteControl::saveSettings(QSettings *settings) const
{
if (rc_port != 7356)
settings->setValue("remote_control/port", rc_port);
else
settings->remove("remote_control/port");
if ((rc_allowed_hosts.count() != 1) || (rc_allowed_hosts.at(0) != "127.0.0.1"))
settings->setValue("remote_control/allowed_hosts", rc_allowed_hosts);
else
settings->remove("remote_control/allowed_hosts");
}
/*! \brief Set new network port.
* \param port The new network port.
*
* If the server is running it will be restarted.
*
*/
void RemoteControl::setPort(int port)
{
if (port == rc_port)
return;
rc_port = port;
if (rc_server.isListening())
{
rc_server.close();
rc_server.listen(QHostAddress::Any, rc_port);
}
}
void RemoteControl::setHosts(QStringList hosts)
{
rc_allowed_hosts.clear();
for (int i = 0; i < hosts.count(); i++)
rc_allowed_hosts << hosts.at(i);
}
/*! \brief Accept a new client connection.
*
* This slot is called when a client opens a new connection.
*/
void RemoteControl::acceptConnection()
{
rc_socket = rc_server.nextPendingConnection();
// check if host is allowed
QString address = rc_socket->peerAddress().toString();
if (rc_allowed_hosts.indexOf(address) == -1)
{
qDebug() << "Connection attempt from" << address << "(not in allowed list)";
rc_socket->close();
}
else
{
connect(rc_socket, SIGNAL(readyRead()), this, SLOT(startRead()));
}
}
/*! \brief Start reading from the socket.
*
* This slot is called when the client TCP socket emits a readyRead() signal,
* i.e. when there is data to read.
*/
void RemoteControl::startRead()
{
char buffer[1024] = {0};
int bytes_read;
qint64 freq;
bytes_read = rc_socket->readLine(buffer, 1024);
if (bytes_read < 2) // command + '\n'
return;
if (buffer[0] == 'F')
{
// set frequency
if (sscanf(buffer,"F %lld\n", &freq) == 1)
{
setNewRemoteFreq(freq);
rc_socket->write("RPRT 0\n");
}
else
{
rc_socket->write("RPRT 1\n");
}
}
else if (buffer[0] == 'f')
{
// get frequency
rc_socket->write(QString("%1\n").arg(rc_freq).toLatin1());
}
else if (buffer[0] == 'c')
{
// FIXME: for now we assume 'close' command
rc_socket->close();
}
// Gpredict / Gqrx specific commands:
// AOS - satellite AOS event
// LOS - satellite LOS event
else if (bytes_read >= 4 && buffer[1] == 'O' && buffer[2] == 'S')
{
if (buffer[0] == 'A')
{
emit satAosEvent();
rc_socket->write("RPRT 0\n");
}
else if (buffer[0] == 'L')
{
emit satLosEvent();
rc_socket->write("RPRT 0\n");
}
else
{
rc_socket->write("RPRT 1\n");
}
}
else
{
// respond with an error
rc_socket->write("RPRT 1\n");
}
}
/*! \brief Slot called when the receiver is tuned to a new frequency.
* \param freq The new frequency in Hz.
*
* Note that this is the frequency gqrx is receiveing on, i.e. the
* hardware frequency + the filter offset.
*/
void RemoteControl::setNewFrequency(qint64 freq)
{
rc_freq = freq;
}
/*! \brief Slot called when the filter offset is changed. */
void RemoteControl::setFilterOffset(qint64 freq)
{
rc_filter_offset = freq;
}
void RemoteControl::setBandwidth(qint64 bw)
{
// we want to leave some margin
bw_half = 0.9 * (bw / 2);
}
/*! \brief New remote frequency received. */
void RemoteControl::setNewRemoteFreq(qint64 freq)
{
qint64 delta = freq - rc_freq;
if (abs(rc_filter_offset + delta) < bw_half)
{
// move filter offset
rc_filter_offset += delta;
emit newFilterOffset(rc_filter_offset);
}
else
{
// move rx freqeucy and let MainWindow deal with it
// (will usually change hardware PLL)
emit newFrequency(freq);
}
rc_freq = freq;
}
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/remote_control.h 0000664 0000000 0000000 00000006256 12260363731 0023401 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef REMOTE_CONTROL_H
#define REMOTE_CONTROL_H
#include
#include
#include
#include
#include
#include
/*! \brief Simple TCP server for remote control.
*
* The TCP interface is compatible with the hamlib rigtctld so that applications
* gpredict can be used with gqrx without any modifications.
*
* The hamlib rigctld protocol is described in the man page
* http://hamlib.sourceforge.net/pdf/rigctld.8.pdf
* but here is a summary.
*
* client: F 144500000\n # set frequency in Hz
* gqrx: RPRT 0\n # 0 means no error
*
* client: f\n # get frequency
* gqrx: 144500000\n # gqrx replies with frequency in Hz
*
* We also have some gqrx specific commands:
*
* close: Close connection (useful for interactive telnet sessions).
*
*
* FIXME: The server code is very minimalistic and probably not very robust.
*/
class RemoteControl : public QObject
{
Q_OBJECT
public:
explicit RemoteControl(QObject *parent = 0);
~RemoteControl();
void start_server(void);
void stop_server(void);
void readSettings(QSettings *settings);
void saveSettings(QSettings *settings) const;
void setPort(int port);
int getPort(void) const
{
return rc_port;
}
void setHosts(QStringList hosts);
QStringList getHosts(void) const
{
return rc_allowed_hosts;
}
public slots:
void setNewFrequency(qint64 freq);
void setFilterOffset(qint64 freq);
void setBandwidth(qint64 bw);
signals:
void newFrequency(qint64 freq);
void newFilterOffset(qint64 offset);
void satAosEvent(void); /*! Satellite AOS event received through the socket. */
void satLosEvent(void); /*! Satellite LOS event received through the socket. */
private slots:
void acceptConnection();
void startRead();
private:
QTcpServer rc_server; /*!< The active server object. */
QTcpSocket* rc_socket; /*!< The active socket object. */
QStringList rc_allowed_hosts; /*!< Hosts where we accept connection from. */
int rc_port; /*!< The port we are listening on. */
qint64 rc_freq;
qint64 rc_filter_offset;
qint64 bw_half;
void setNewRemoteFreq(qint64 freq);
};
#endif // REMOTE_CONTROL_H
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/remote_control_settings.cpp 0000664 0000000 0000000 00000005711 12260363731 0025647 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include "remote_control_settings.h"
#include "ui_remote_control_settings.h"
RemoteControlSettings::RemoteControlSettings(QWidget *parent) :
QDialog(parent),
ui(new Ui::RemoteControlSettings)
{
ui->setupUi(this);
}
RemoteControlSettings::~RemoteControlSettings()
{
delete ui;
}
/*! \brief Set new network port.
* \param port The new network port.
*/
void RemoteControlSettings::setPort(int port)
{
ui->portSpinBox->setValue(port);
}
/*! \brief Get current value from the port spin box.
* \return The current port value.
*/
int RemoteControlSettings::getPort(void) const
{
return ui->portSpinBox->value();
}
/*! \brief Add items to the list of allowed hosts.
* \param hosts A list with the IP addresses of the allowed hosts.
*
* Note that setting the list wil lclear the current contents of the
* list widget.
*/
void RemoteControlSettings::setHosts(QStringList hosts)
{
ui->hostListWidget->clear();
ui->hostListWidget->addItems(hosts);
}
/*! \brief Get list of allowed hosts. */
QStringList RemoteControlSettings::getHosts(void) const
{
QStringList list;
for (int i = 0; i < ui->hostListWidget->count(); i++)
{
list << ui->hostListWidget->item(i)->text();
}
return list;
}
/*! \brief Add a new entry to the list of allowed hosts.
*
* The function inserts a new entry at the end of the list and enables
* editing.
*/
void RemoteControlSettings::on_hostAddButton_clicked(void)
{
ui->hostListWidget->addItem(tr("Enter IP"));
QListWidgetItem *item = ui->hostListWidget->item(ui->hostListWidget->count()-1);
item->setFlags(item->flags() | Qt::ItemIsEditable);
ui->hostListWidget->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
ui->hostListWidget->editItem(item);
}
/*! \brief Delete the selected entries from the list of allowed hosts. */
void RemoteControlSettings::on_hostDelButton_clicked(void)
{
// wondering WTF?
// see http://stackoverflow.com/questions/7008423/how-do-i-remove-all-the-selected-items-in-a-qlistwidget
qDeleteAll(ui->hostListWidget->selectedItems());
}
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/remote_control_settings.h 0000664 0000000 0000000 00000003065 12260363731 0025314 0 ustar 00root root 0000000 0000000 /* -*- c++ -*- */
/*
* Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
* http://gqrx.dk/
*
* Copyright 2013 Alexandru Csete OZ9AEC.
*
* Gqrx is free software; you can 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, or (at your option)
* any later version.
*
* Gqrx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef REMOTE_CONTROL_SETTINGS_H
#define REMOTE_CONTROL_SETTINGS_H
#include
#include
#include
namespace Ui {
class RemoteControlSettings;
}
/*! \brief Class to configure remote control settiongs. */
class RemoteControlSettings : public QDialog
{
Q_OBJECT
public:
explicit RemoteControlSettings(QWidget *parent = 0);
~RemoteControlSettings();
void setPort(int port);
int getPort(void) const;
void setHosts(QStringList hosts);
QStringList getHosts(void) const;
private slots:
void on_hostAddButton_clicked(void);
void on_hostDelButton_clicked(void);
private:
Ui::RemoteControlSettings *ui;
};
#endif // REMOTE_CONTROL_SETTINGS_H
gqrx-sdr-2.2.0.74.d97bd7/applications/gqrx/remote_control_settings.ui 0000664 0000000 0000000 00000013470 12260363731 0025503 0 ustar 00root root 0000000 0000000
RemoteControlSettings
0
0
314
269
Gqrx remote control settings
:/icons/icons/settings.svg:/icons/icons/settings.svg
-
-
<html><head/><body><p>Select which port to listen on</p><p>(0 selects a random port)</p></body></html>
Listen on port
-
75
0
<html><head/><body><p>Select which port to listen on</p><p>(0 selects a random port)</p></body></html>
0
65535
7356
-
Qt::Horizontal
40
20
-
List of IP addresses where gqrx should accept connections from
Allowed hosts
-
List of IP addresses where gqrx should accept connections from
QAbstractItemView::ExtendedSelection
QListView::Fixed
-
127.0.0.1
ItemIsSelectable|ItemIsEditable|ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled
-
-
56
16777215
Add a new host to the list
Add
-
56
16777215
Delete the selected host from the list
Del
-
Qt::Vertical
20
40
-
Qt::Horizontal
-
Qt::Horizontal
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
buttonBox
accepted()
RemoteControlSettings
accept()
248
254
157
274
buttonBox
rejected()
RemoteControlSettings
reject()
316
260
286
274
gqrx-sdr-2.2.0.74.d97bd7/dsp/ 0000775 0000000 0000000 00000000000 12260363731 0015303 5 ustar 00root root 0000000 0000000 gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/ 0000775 0000000 0000000 00000000000 12260363731 0016532 5 ustar 00root root 0000000 0000000 gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/cafsk12.cpp 0000664 0000000 0000000 00000034103 12260363731 0020471 0 ustar 00root root 0000000 0000000 /*
* cafsk12.cpp -- AFSK1200 demodulator class
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
*
* Copyright (C) 2011 Alexandru Csete (oz9aec at gmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include
#include
#include
#include
#include
#include "filter.h"
#include "cafsk12.h"
CAfsk12::CAfsk12(QObject *parent) :
QObject(parent)
{
state = (demod_state *) malloc(sizeof(demod_state));
reset();
}
CAfsk12::~CAfsk12()
{
free(state);
}
/*! \brief Reset the decoder. */
void CAfsk12::reset()
{
float f;
int i;
hdlc_init(state);
memset(&state->l1.afsk12, 0, sizeof(state->l1.afsk12));
for (f = 0, i = 0; i < CORRLEN; i++) {
corr_mark_i[i] = cos(f);
corr_mark_q[i] = sin(f);
f += 2.0*M_PI*FREQ_MARK/FREQ_SAMP;
}
for (f = 0, i = 0; i < CORRLEN; i++) {
corr_space_i[i] = cos(f);
corr_space_q[i] = sin(f);
f += 2.0*M_PI*FREQ_SPACE/FREQ_SAMP;
}
}
void CAfsk12::demod(float *buffer, int length)
{
float f;
unsigned char curbit;
if (state->l1.afsk12.subsamp) {
int numfill = SUBSAMP - state->l1.afsk12.subsamp;
if (length < numfill) {
state->l1.afsk12.subsamp += length;
return;
}
buffer += numfill;
length -= numfill;
state->l1.afsk12.subsamp = 0;
}
for (; length >= SUBSAMP; length -= SUBSAMP, buffer += SUBSAMP) {
f = fsqr(mac(buffer, corr_mark_i, CORRLEN)) +
fsqr(mac(buffer, corr_mark_q, CORRLEN)) -
fsqr(mac(buffer, corr_space_i, CORRLEN)) -
fsqr(mac(buffer, corr_space_q, CORRLEN));
state->l1.afsk12.dcd_shreg <<= 1;
state->l1.afsk12.dcd_shreg |= (f > 0);
verbprintf(10, "%c", '0'+(state->l1.afsk12.dcd_shreg & 1));
/*
* check if transition
*/
if ((state->l1.afsk12.dcd_shreg ^ (state->l1.afsk12.dcd_shreg >> 1)) & 1) {
if (state->l1.afsk12.sphase < (0x8000u-(SPHASEINC/2)))
state->l1.afsk12.sphase += SPHASEINC/8;
else
state->l1.afsk12.sphase -= SPHASEINC/8;
}
state->l1.afsk12.sphase += SPHASEINC;
if (state->l1.afsk12.sphase >= 0x10000u) {
state->l1.afsk12.sphase &= 0xffffu;
state->l1.afsk12.lasts <<= 1;
state->l1.afsk12.lasts |= state->l1.afsk12.dcd_shreg & 1;
curbit = (state->l1.afsk12.lasts ^
(state->l1.afsk12.lasts >> 1) ^ 1) & 1;
verbprintf(9, " %c ", '0'+curbit);
hdlc_rxbit(state, curbit);
}
}
state->l1.afsk12.subsamp = length;
}
/** HDLC functions **/
/*
* the CRC routines are stolen from WAMPES
* by Dieter Deyke
*/
static const unsigned short crc_ccitt_table[] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
void CAfsk12::hdlc_init(struct demod_state *s)
{
memset(&s->l2.hdlc, 0, sizeof(s->l2.hdlc));
}
void CAfsk12::hdlc_rxbit(struct demod_state *s, int bit)
{
s->l2.hdlc.rxbitstream <<= 1;
s->l2.hdlc.rxbitstream |= !!bit;
if ((s->l2.hdlc.rxbitstream & 0xff) == 0x7e) {
if (s->l2.hdlc.rxstate && (s->l2.hdlc.rxptr - s->l2.hdlc.rxbuf) > 2)
ax25_disp_packet(s->l2.hdlc.rxbuf, s->l2.hdlc.rxptr - s->l2.hdlc.rxbuf);
s->l2.hdlc.rxstate = 1;
s->l2.hdlc.rxptr = s->l2.hdlc.rxbuf;
s->l2.hdlc.rxbitbuf = 0x80;
return;
}
if ((s->l2.hdlc.rxbitstream & 0x7f) == 0x7f) {
s->l2.hdlc.rxstate = 0;
return;
}
if (!s->l2.hdlc.rxstate)
return;
if ((s->l2.hdlc.rxbitstream & 0x3f) == 0x3e) /* stuffed bit */
return;
if (s->l2.hdlc.rxbitstream & 1)
s->l2.hdlc.rxbitbuf |= 0x100;
if (s->l2.hdlc.rxbitbuf & 1) {
if (s->l2.hdlc.rxptr >= s->l2.hdlc.rxbuf+sizeof(s->l2.hdlc.rxbuf)) {
s->l2.hdlc.rxstate = 0;
verbprintf(1, "Error: packet size too large\n");
return;
}
*s->l2.hdlc.rxptr++ = s->l2.hdlc.rxbitbuf >> 1;
s->l2.hdlc.rxbitbuf = 0x80;
return;
}
s->l2.hdlc.rxbitbuf >>= 1;
}
static int verbose_level = 2;
void CAfsk12::verbprintf(int verb_level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (verb_level <= verbose_level) {
vfprintf(stdout, fmt, args);
fflush(stdout);
}
va_end(args);
}
static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
{
unsigned int crc = 0xffff;
for (; cnt > 0; cnt--)
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
return (crc & 0xffff) == 0xf0b8;
}
void CAfsk12::ax25_disp_packet(unsigned char *bp, unsigned int len)
{
QString message;
unsigned char v1=1,cmd=0;
unsigned char i,j;
verbprintf(6, "AX.25 PKT; L=%d\n", len);
if (!bp || len < 10)
return;
#if 1
if (!check_crc_ccitt(bp, len)) {
verbprintf(6, "CRC check failed\n");
return;
}
#endif
/* get current time that will be prepended to packet display */
QTime time = QTime::currentTime();
len -= 2;
if (bp[1] & 1) {
/*
* FlexNet Header Compression
*/
v1 = 0;
cmd = (bp[1] & 2) != 0;
verbprintf(0, "AFSK1200: fm ? to ");
message.append(QString("%1$ fm ? to ").arg(time.toString("hh:mm:ss")));
i = (bp[2] >> 2) & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
i = ((bp[2] << 4) | ((bp[3] >> 4) & 0xf)) & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
i = ((bp[3] << 2) | ((bp[4] >> 6) & 3)) & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
i = bp[4] & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
i = (bp[5] >> 2) & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
i = ((bp[5] << 4) | ((bp[6] >> 4) & 0xf)) & 0x3f;
if (i) {
verbprintf(0, "%c",i+0x20);
message.append(QChar(i+0x20));
}
verbprintf(0, "-%u QSO Nr %u", bp[6] & 0xf, (bp[0] << 6) | (bp[1] >> 2));
message.append(QString("-%1 QSO Nr %1").arg(bp[6] & 0xf).arg((bp[0] << 6) | (bp[1] >> 2)));
bp += 7;
len -= 7;
} else {
/*
* normal header
*/
if (len < 15)
goto finished;
if ((bp[6] & 0x80) != (bp[13] & 0x80)) {
v1 = 0;
cmd = (bp[6] & 0x80);
}
verbprintf(0, "AFSK1200: fm ");
message.append(QString("%1$ fm ").arg(time.toString("hh:mm:ss")));
for(i = 7; i < 13; i++)
if ((bp[i] &0xfe) != 0x40) {
verbprintf(0, "%c",bp[i] >> 1);
message.append(QChar(bp[i] >> 1));
}
verbprintf(0, "-%u to ",(bp[13] >> 1) & 0xf);
message.append(QString("-%1 to ").arg((bp[13] >> 1) & 0xf));
for(i = 0; i < 6; i++)
if ((bp[i] &0xfe) != 0x40) {
verbprintf(0, "%c",bp[i] >> 1);
message.append(QChar(bp[i] >> 1));
}
verbprintf(0, "-%u",(bp[6] >> 1) & 0xf);
message.append(QString("-%1").arg((bp[6] >> 1) & 0xf));
bp += 14;
len -= 14;
if ((!(bp[-1] & 1)) && (len >= 7)) {
verbprintf(0, " via ");
message.append(" via ");
}
while ((!(bp[-1] & 1)) && (len >= 7)) {
for(i = 0; i < 6; i++)
if ((bp[i] &0xfe) != 0x40) {
verbprintf(0, "%c",bp[i] >> 1);
message.append(QChar(bp[i] >> 1));
}
verbprintf(0, "-%u",(bp[6] >> 1) & 0xf);
message.append(QString("-%1").arg((bp[6] >> 1) & 0xf));
bp += 7;
len -= 7;
if ((!(bp[-1] & 1)) && (len >= 7)) {
verbprintf(0, ",");
message.append(",");
}
}
}
if(!len)
goto finished;
i = *bp++;
len--;
j = v1 ? ((i & 0x10) ? '!' : ' ') :
((i & 0x10) ? (cmd ? '+' : '-') : (cmd ? '^' : 'v'));
if (!(i & 1)) {
/* Info frame */
verbprintf(0, " I%u%u%c",(i >> 5) & 7,(i >> 1) & 7,j);
message.append(QString(" I%1%2%3").arg((i >> 5) & 7).arg((i >> 1) & 7).arg(j));
}
else if (i & 2) {
/* U frame */
switch (i & (~0x10)) {
case 0x03:
verbprintf(0, " UI%c",j);
message.append(QString(" UI%1").arg(QChar(j)));
break;
case 0x2f:
verbprintf(0, " SABM%c",j);
message.append(QString(" SABM%1").arg(QChar(j)));
break;
case 0x43:
verbprintf(0, " DISC%c",j);
message.append(QString(" DISC%1").arg(QChar(j)));
break;
case 0x0f:
verbprintf(0, " DM%c",j);
message.append(QString(" DM%1").arg(QChar(j)));
break;
case 0x63:
verbprintf(0, " UA%c",j);
message.append(QString(" UA%1").arg(QChar(j)));
break;
case 0x87:
verbprintf(0, " FRMR%c",j);
message.append(QString(" FRMR%1").arg(QChar(j)));
break;
default:
verbprintf(0, " unknown U (0x%x)%c",i & (~0x10),j);
message.append(QString(" unknown U (0x%1)%2").arg(i & (~0x10),0,16).arg(QChar(j)));
break;
}
} else {
/* supervisory */
switch (i & 0xf) {
case 0x1:
verbprintf(0, " RR%u%c",(i >> 5) & 7,j);
message.append(QString(" RR%1%2").arg((i >> 5) & 7).arg(QChar(j)));
break;
case 0x5:
verbprintf(0, " RNR%u%c",(i >> 5) & 7,j);
message.append(QString(" RNR%1%2").arg((i >> 5) & 7).arg(QChar(j)));
break;
case 0x9:
verbprintf(0, " REJ%u%c",(i >> 5) & 7,j);
message.append(QString(" REJ%1%2").arg((i >> 5) & 7).arg(QChar(j)));
break;
default:
verbprintf(0, " unknown S (0x%x)%u%c", i & 0xf, (i >> 5) & 7, j);
message.append(QString(" unknown S (0x%1)%2%3").arg(i & 0xf,0,16).arg((i >> 5) & 7).arg(QChar(j)));
break;
}
}
if (!len) {
verbprintf(0, "\n");
//message.append("\n");
goto finished;
}
i = *bp++;
verbprintf(0, " pid=%02X\n", i);
message.append(QString(" pid=%1\n ").arg(i,0,16).toUpper());
len--;
j = 0;
while (len) {
i = *bp++;
if ((i >= 32) && (i < 128)) {
verbprintf(0, "%c",i);
message.append(QChar(i));
}
else if (i == 13) {
if (j) {
verbprintf(0, "\n");
//message.append("\n");
}
j = 0;
}
else {
verbprintf(0, ".");
message.append(".");
}
if (i >= 32)
j = 1;
len--;
}
if (j) {
verbprintf(0, "\n");
//message.append("\n");
}
/* I just secured myself a ticket to hell */
finished:
if (message.size() > 0) {
emit newMessage(message);
}
}
gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/cafsk12.h 0000664 0000000 0000000 00000011120 12260363731 0020130 0 ustar 00root root 0000000 0000000 /*
* cafsk12.h -- AFSK1200 demodulator class
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
*
* Copyright (C) 2011 Alexandru Csete (oz9aec at gmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CAFSK12_H
#define CAFSK12_H
#include
extern const float costabf[0x400];
#define COS(x) costabf[(((x)>>6)&0x3ffu)]
#define SIN(x) COS((x)+0xc000)
/*
* Standard TCM3105 clock frequency: 4.4336MHz
* Mark frequency: 2200 Hz
* Space frequency: 1200 Hz
*/
#define FREQ_MARK 1200
#define FREQ_SPACE 2200
#define FREQ_SAMP 22050
#define BAUD 1200
#define SUBSAMP 2
#define CORRLEN ((int)(FREQ_SAMP/BAUD))
#define SPHASEINC (0x10000u*BAUD*SUBSAMP/FREQ_SAMP)
struct demod_state {
const struct demod_param *dem_par;
union {
struct l2_state_hdlc {
unsigned char rxbuf[512];
unsigned char *rxptr;
unsigned int rxstate;
unsigned int rxbitstream;
unsigned int rxbitbuf;
} hdlc;
struct l2_state_pocsag {
unsigned long rx_data;
struct l2_pocsag_rx {
unsigned char rx_sync;
unsigned char rx_word;
unsigned char rx_bit;
char func;
unsigned long adr;
unsigned char buffer[128];
unsigned int numnibbles;
} rx[2];
} pocsag;
} l2;
union {
struct l1_state_poc5 {
unsigned int dcd_shreg;
unsigned int sphase;
unsigned int subsamp;
} poc5;
struct l1_state_poc12 {
unsigned int dcd_shreg;
unsigned int sphase;
unsigned int subsamp;
} poc12;
struct l1_state_poc24 {
unsigned int dcd_shreg;
unsigned int sphase;
} poc24;
struct l1_state_afsk12 {
unsigned int dcd_shreg;
unsigned int sphase;
unsigned int lasts;
unsigned int subsamp;
} afsk12;
struct l1_state_afsk24 {
unsigned int dcd_shreg;
unsigned int sphase;
unsigned int lasts;
} afsk24;
struct l1_state_hapn48 {
unsigned int shreg;
unsigned int sphase;
float lvllo, lvlhi;
} hapn48;
struct l1_state_fsk96 {
unsigned int dcd_shreg;
unsigned int sphase;
unsigned int descram;
} fsk96;
struct l1_state_dtmf {
unsigned int ph[8];
float energy[4];
float tenergy[4][16];
int blkcount;
int lastch;
} dtmf;
struct l1_state_zvei {
unsigned int ph[16];
float energy[4];
float tenergy[4][32];
int blkcount;
int lastch;
} zvei;
struct l1_state_scope {
int datalen;
int dispnum;
float data[512];
} scope;
} l1;
};
struct demod_param {
const char *name;
unsigned int samplerate;
unsigned int overlap;
//void (*init)(struct demod_state *s);
//void (*demod)(struct demod_state *s, float *buffer, int length);
};
class CAfsk12 : public QObject
{
Q_OBJECT
public:
explicit CAfsk12(QObject *parent = 0);
~CAfsk12();
void demod(float *buffer, int length);
void reset();
signals:
void newMessage(const QString &message);
public slots:
private:
float corr_mark_i[CORRLEN];
float corr_mark_q[CORRLEN];
float corr_space_i[CORRLEN];
float corr_space_q[CORRLEN];
struct demod_state *state;
/* HDLC functions */
void hdlc_init(struct demod_state *s);
void hdlc_rxbit(struct demod_state *s, int bit);
void verbprintf(int verb_level, const char *fmt, ...);
void ax25_disp_packet(unsigned char *bp, unsigned int len);
};
#endif // CAFSK12_H
gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/costabf.c 0000664 0000000 0000000 00000035121 12260363731 0020321 0 ustar 00root root 0000000 0000000 /*
* This file is machine generated, DO NOT EDIT!
*/
float costabf[1024] = {
1.000000000, 0.999981165, 0.999924719, 0.999830604,
0.999698818, 0.999529421, 0.999322355, 0.999077737,
0.998795450, 0.998475552, 0.998118103, 0.997723043,
0.997290432, 0.996820271, 0.996312618, 0.995767415,
0.995184720, 0.994564593, 0.993906975, 0.993211925,
0.992479563, 0.991709769, 0.990902662, 0.990058184,
0.989176512, 0.988257587, 0.987301409, 0.986308098,
0.985277653, 0.984210074, 0.983105481, 0.981963873,
0.980785251, 0.979569793, 0.978317380, 0.977028131,
0.975702107, 0.974339366, 0.972939968, 0.971503913,
0.970031261, 0.968522072, 0.966976464, 0.965394437,
0.963776052, 0.962121427, 0.960430503, 0.958703458,
0.956940353, 0.955141187, 0.953306019, 0.951435030,
0.949528158, 0.947585583, 0.945607305, 0.943593442,
0.941544056, 0.939459205, 0.937339008, 0.935183525,
0.932992816, 0.930766940, 0.928506076, 0.926210225,
0.923879504, 0.921514034, 0.919113874, 0.916679084,
0.914209783, 0.911706030, 0.909168005, 0.906595707,
0.903989315, 0.901348829, 0.898674488, 0.895966232,
0.893224299, 0.890448749, 0.887639642, 0.884797096,
0.881921291, 0.879012227, 0.876070082, 0.873094976,
0.870086968, 0.867046237, 0.863972843, 0.860866964,
0.857728601, 0.854557991, 0.851355195, 0.848120332,
0.844853580, 0.841554999, 0.838224709, 0.834862888,
0.831469595, 0.828045070, 0.824589312, 0.821102500,
0.817584813, 0.814036310, 0.810457170, 0.806847572,
0.803207517, 0.799537241, 0.795836926, 0.792106569,
0.788346410, 0.784556568, 0.780737221, 0.776888490,
0.773010433, 0.769103348, 0.765167236, 0.761202395,
0.757208824, 0.753186822, 0.749136388, 0.745057762,
0.740951121, 0.736816585, 0.732654274, 0.728464365,
0.724247098, 0.720002532, 0.715730846, 0.711432219,
0.707106769, 0.702754736, 0.698376238, 0.693971455,
0.689540565, 0.685083687, 0.680601001, 0.676092684,
0.671558976, 0.666999936, 0.662415802, 0.657806695,
0.653172851, 0.648514390, 0.643831551, 0.639124453,
0.634393275, 0.629638255, 0.624859512, 0.620057225,
0.615231574, 0.610382795, 0.605511069, 0.600616455,
0.595699310, 0.590759695, 0.585797846, 0.580813944,
0.575808167, 0.570780754, 0.565731823, 0.560661554,
0.555570245, 0.550457954, 0.545324981, 0.540171444,
0.534997642, 0.529803634, 0.524589658, 0.519356012,
0.514102757, 0.508830130, 0.503538370, 0.498227656,
0.492898196, 0.487550169, 0.482183784, 0.476799220,
0.471396744, 0.465976506, 0.460538715, 0.455083579,
0.449611336, 0.444122136, 0.438616246, 0.433093816,
0.427555084, 0.422000259, 0.416429549, 0.410843164,
0.405241311, 0.399624199, 0.393992037, 0.388345033,
0.382683426, 0.377007425, 0.371317208, 0.365612984,
0.359895051, 0.354163527, 0.348418683, 0.342660725,
0.336889863, 0.331106305, 0.325310290, 0.319502026,
0.313681751, 0.307849646, 0.302005947, 0.296150893,
0.290284663, 0.284407526, 0.278519690, 0.272621363,
0.266712755, 0.260794103, 0.254865646, 0.248927608,
0.242980182, 0.237023607, 0.231058106, 0.225083917,
0.219101235, 0.213110313, 0.207111374, 0.201104641,
0.195090324, 0.189068660, 0.183039889, 0.177004218,
0.170961887, 0.164913118, 0.158858150, 0.152797192,
0.146730468, 0.140658244, 0.134580702, 0.128498107,
0.122410677, 0.116318628, 0.110222206, 0.104121633,
0.098017141, 0.091908954, 0.085797310, 0.079682440,
0.073564567, 0.067443922, 0.061320737, 0.055195246,
0.049067676, 0.042938258, 0.036807224, 0.030674804,
0.024541229, 0.018406730, 0.012271538, 0.006135885,
0.000000000, -0.006135885, -0.012271538, -0.018406730,
-0.024541229, -0.030674804, -0.036807224, -0.042938258,
-0.049067676, -0.055195246, -0.061320737, -0.067443922,
-0.073564567, -0.079682440, -0.085797310, -0.091908954,
-0.098017141, -0.104121633, -0.110222206, -0.116318628,
-0.122410677, -0.128498107, -0.134580702, -0.140658244,
-0.146730468, -0.152797192, -0.158858150, -0.164913118,
-0.170961887, -0.177004218, -0.183039889, -0.189068660,
-0.195090324, -0.201104641, -0.207111374, -0.213110313,
-0.219101235, -0.225083917, -0.231058106, -0.237023607,
-0.242980182, -0.248927608, -0.254865646, -0.260794103,
-0.266712755, -0.272621363, -0.278519690, -0.284407526,
-0.290284663, -0.296150893, -0.302005947, -0.307849646,
-0.313681751, -0.319502026, -0.325310290, -0.331106305,
-0.336889863, -0.342660725, -0.348418683, -0.354163527,
-0.359895051, -0.365612984, -0.371317208, -0.377007425,
-0.382683426, -0.388345033, -0.393992037, -0.399624199,
-0.405241311, -0.410843164, -0.416429549, -0.422000259,
-0.427555084, -0.433093816, -0.438616246, -0.444122136,
-0.449611336, -0.455083579, -0.460538715, -0.465976506,
-0.471396744, -0.476799220, -0.482183784, -0.487550169,
-0.492898196, -0.498227656, -0.503538370, -0.508830130,
-0.514102757, -0.519356012, -0.524589658, -0.529803634,
-0.534997642, -0.540171444, -0.545324981, -0.550457954,
-0.555570245, -0.560661554, -0.565731823, -0.570780754,
-0.575808167, -0.580813944, -0.585797846, -0.590759695,
-0.595699310, -0.600616455, -0.605511069, -0.610382795,
-0.615231574, -0.620057225, -0.624859512, -0.629638255,
-0.634393275, -0.639124453, -0.643831551, -0.648514390,
-0.653172851, -0.657806695, -0.662415802, -0.666999936,
-0.671558976, -0.676092684, -0.680601001, -0.685083687,
-0.689540565, -0.693971455, -0.698376238, -0.702754736,
-0.707106769, -0.711432219, -0.715730846, -0.720002532,
-0.724247098, -0.728464365, -0.732654274, -0.736816585,
-0.740951121, -0.745057762, -0.749136388, -0.753186822,
-0.757208824, -0.761202395, -0.765167236, -0.769103348,
-0.773010433, -0.776888490, -0.780737221, -0.784556568,
-0.788346410, -0.792106569, -0.795836926, -0.799537241,
-0.803207517, -0.806847572, -0.810457170, -0.814036310,
-0.817584813, -0.821102500, -0.824589312, -0.828045070,
-0.831469595, -0.834862888, -0.838224709, -0.841554999,
-0.844853580, -0.848120332, -0.851355195, -0.854557991,
-0.857728601, -0.860866964, -0.863972843, -0.867046237,
-0.870086968, -0.873094976, -0.876070082, -0.879012227,
-0.881921291, -0.884797096, -0.887639642, -0.890448749,
-0.893224299, -0.895966232, -0.898674488, -0.901348829,
-0.903989315, -0.906595707, -0.909168005, -0.911706030,
-0.914209783, -0.916679084, -0.919113874, -0.921514034,
-0.923879504, -0.926210225, -0.928506076, -0.930766940,
-0.932992816, -0.935183525, -0.937339008, -0.939459205,
-0.941544056, -0.943593442, -0.945607305, -0.947585583,
-0.949528158, -0.951435030, -0.953306019, -0.955141187,
-0.956940353, -0.958703458, -0.960430503, -0.962121427,
-0.963776052, -0.965394437, -0.966976464, -0.968522072,
-0.970031261, -0.971503913, -0.972939968, -0.974339366,
-0.975702107, -0.977028131, -0.978317380, -0.979569793,
-0.980785251, -0.981963873, -0.983105481, -0.984210074,
-0.985277653, -0.986308098, -0.987301409, -0.988257587,
-0.989176512, -0.990058184, -0.990902662, -0.991709769,
-0.992479563, -0.993211925, -0.993906975, -0.994564593,
-0.995184720, -0.995767415, -0.996312618, -0.996820271,
-0.997290432, -0.997723043, -0.998118103, -0.998475552,
-0.998795450, -0.999077737, -0.999322355, -0.999529421,
-0.999698818, -0.999830604, -0.999924719, -0.999981165,
-1.000000000, -0.999981165, -0.999924719, -0.999830604,
-0.999698818, -0.999529421, -0.999322355, -0.999077737,
-0.998795450, -0.998475552, -0.998118103, -0.997723043,
-0.997290432, -0.996820271, -0.996312618, -0.995767415,
-0.995184720, -0.994564593, -0.993906975, -0.993211925,
-0.992479563, -0.991709769, -0.990902662, -0.990058184,
-0.989176512, -0.988257587, -0.987301409, -0.986308098,
-0.985277653, -0.984210074, -0.983105481, -0.981963873,
-0.980785251, -0.979569793, -0.978317380, -0.977028131,
-0.975702107, -0.974339366, -0.972939968, -0.971503913,
-0.970031261, -0.968522072, -0.966976464, -0.965394437,
-0.963776052, -0.962121427, -0.960430503, -0.958703458,
-0.956940353, -0.955141187, -0.953306019, -0.951435030,
-0.949528158, -0.947585583, -0.945607305, -0.943593442,
-0.941544056, -0.939459205, -0.937339008, -0.935183525,
-0.932992816, -0.930766940, -0.928506076, -0.926210225,
-0.923879504, -0.921514034, -0.919113874, -0.916679084,
-0.914209783, -0.911706030, -0.909168005, -0.906595707,
-0.903989315, -0.901348829, -0.898674488, -0.895966232,
-0.893224299, -0.890448749, -0.887639642, -0.884797096,
-0.881921291, -0.879012227, -0.876070082, -0.873094976,
-0.870086968, -0.867046237, -0.863972843, -0.860866964,
-0.857728601, -0.854557991, -0.851355195, -0.848120332,
-0.844853580, -0.841554999, -0.838224709, -0.834862888,
-0.831469595, -0.828045070, -0.824589312, -0.821102500,
-0.817584813, -0.814036310, -0.810457170, -0.806847572,
-0.803207517, -0.799537241, -0.795836926, -0.792106569,
-0.788346410, -0.784556568, -0.780737221, -0.776888490,
-0.773010433, -0.769103348, -0.765167236, -0.761202395,
-0.757208824, -0.753186822, -0.749136388, -0.745057762,
-0.740951121, -0.736816585, -0.732654274, -0.728464365,
-0.724247098, -0.720002532, -0.715730846, -0.711432219,
-0.707106769, -0.702754736, -0.698376238, -0.693971455,
-0.689540565, -0.685083687, -0.680601001, -0.676092684,
-0.671558976, -0.666999936, -0.662415802, -0.657806695,
-0.653172851, -0.648514390, -0.643831551, -0.639124453,
-0.634393275, -0.629638255, -0.624859512, -0.620057225,
-0.615231574, -0.610382795, -0.605511069, -0.600616455,
-0.595699310, -0.590759695, -0.585797846, -0.580813944,
-0.575808167, -0.570780754, -0.565731823, -0.560661554,
-0.555570245, -0.550457954, -0.545324981, -0.540171444,
-0.534997642, -0.529803634, -0.524589658, -0.519356012,
-0.514102757, -0.508830130, -0.503538370, -0.498227656,
-0.492898196, -0.487550169, -0.482183784, -0.476799220,
-0.471396744, -0.465976506, -0.460538715, -0.455083579,
-0.449611336, -0.444122136, -0.438616246, -0.433093816,
-0.427555084, -0.422000259, -0.416429549, -0.410843164,
-0.405241311, -0.399624199, -0.393992037, -0.388345033,
-0.382683426, -0.377007425, -0.371317208, -0.365612984,
-0.359895051, -0.354163527, -0.348418683, -0.342660725,
-0.336889863, -0.331106305, -0.325310290, -0.319502026,
-0.313681751, -0.307849646, -0.302005947, -0.296150893,
-0.290284663, -0.284407526, -0.278519690, -0.272621363,
-0.266712755, -0.260794103, -0.254865646, -0.248927608,
-0.242980182, -0.237023607, -0.231058106, -0.225083917,
-0.219101235, -0.213110313, -0.207111374, -0.201104641,
-0.195090324, -0.189068660, -0.183039889, -0.177004218,
-0.170961887, -0.164913118, -0.158858150, -0.152797192,
-0.146730468, -0.140658244, -0.134580702, -0.128498107,
-0.122410677, -0.116318628, -0.110222206, -0.104121633,
-0.098017141, -0.091908954, -0.085797310, -0.079682440,
-0.073564567, -0.067443922, -0.061320737, -0.055195246,
-0.049067676, -0.042938258, -0.036807224, -0.030674804,
-0.024541229, -0.018406730, -0.012271538, -0.006135885,
-0.000000000, 0.006135885, 0.012271538, 0.018406730,
0.024541229, 0.030674804, 0.036807224, 0.042938258,
0.049067676, 0.055195246, 0.061320737, 0.067443922,
0.073564567, 0.079682440, 0.085797310, 0.091908954,
0.098017141, 0.104121633, 0.110222206, 0.116318628,
0.122410677, 0.128498107, 0.134580702, 0.140658244,
0.146730468, 0.152797192, 0.158858150, 0.164913118,
0.170961887, 0.177004218, 0.183039889, 0.189068660,
0.195090324, 0.201104641, 0.207111374, 0.213110313,
0.219101235, 0.225083917, 0.231058106, 0.237023607,
0.242980182, 0.248927608, 0.254865646, 0.260794103,
0.266712755, 0.272621363, 0.278519690, 0.284407526,
0.290284663, 0.296150893, 0.302005947, 0.307849646,
0.313681751, 0.319502026, 0.325310290, 0.331106305,
0.336889863, 0.342660725, 0.348418683, 0.354163527,
0.359895051, 0.365612984, 0.371317208, 0.377007425,
0.382683426, 0.388345033, 0.393992037, 0.399624199,
0.405241311, 0.410843164, 0.416429549, 0.422000259,
0.427555084, 0.433093816, 0.438616246, 0.444122136,
0.449611336, 0.455083579, 0.460538715, 0.465976506,
0.471396744, 0.476799220, 0.482183784, 0.487550169,
0.492898196, 0.498227656, 0.503538370, 0.508830130,
0.514102757, 0.519356012, 0.524589658, 0.529803634,
0.534997642, 0.540171444, 0.545324981, 0.550457954,
0.555570245, 0.560661554, 0.565731823, 0.570780754,
0.575808167, 0.580813944, 0.585797846, 0.590759695,
0.595699310, 0.600616455, 0.605511069, 0.610382795,
0.615231574, 0.620057225, 0.624859512, 0.629638255,
0.634393275, 0.639124453, 0.643831551, 0.648514390,
0.653172851, 0.657806695, 0.662415802, 0.666999936,
0.671558976, 0.676092684, 0.680601001, 0.685083687,
0.689540565, 0.693971455, 0.698376238, 0.702754736,
0.707106769, 0.711432219, 0.715730846, 0.720002532,
0.724247098, 0.728464365, 0.732654274, 0.736816585,
0.740951121, 0.745057762, 0.749136388, 0.753186822,
0.757208824, 0.761202395, 0.765167236, 0.769103348,
0.773010433, 0.776888490, 0.780737221, 0.784556568,
0.788346410, 0.792106569, 0.795836926, 0.799537241,
0.803207517, 0.806847572, 0.810457170, 0.814036310,
0.817584813, 0.821102500, 0.824589312, 0.828045070,
0.831469595, 0.834862888, 0.838224709, 0.841554999,
0.844853580, 0.848120332, 0.851355195, 0.854557991,
0.857728601, 0.860866964, 0.863972843, 0.867046237,
0.870086968, 0.873094976, 0.876070082, 0.879012227,
0.881921291, 0.884797096, 0.887639642, 0.890448749,
0.893224299, 0.895966232, 0.898674488, 0.901348829,
0.903989315, 0.906595707, 0.909168005, 0.911706030,
0.914209783, 0.916679084, 0.919113874, 0.921514034,
0.923879504, 0.926210225, 0.928506076, 0.930766940,
0.932992816, 0.935183525, 0.937339008, 0.939459205,
0.941544056, 0.943593442, 0.945607305, 0.947585583,
0.949528158, 0.951435030, 0.953306019, 0.955141187,
0.956940353, 0.958703458, 0.960430503, 0.962121427,
0.963776052, 0.965394437, 0.966976464, 0.968522072,
0.970031261, 0.971503913, 0.972939968, 0.974339366,
0.975702107, 0.977028131, 0.978317380, 0.979569793,
0.980785251, 0.981963873, 0.983105481, 0.984210074,
0.985277653, 0.986308098, 0.987301409, 0.988257587,
0.989176512, 0.990058184, 0.990902662, 0.991709769,
0.992479563, 0.993211925, 0.993906975, 0.994564593,
0.995184720, 0.995767415, 0.996312618, 0.996820271,
0.997290432, 0.997723043, 0.998118103, 0.998475552,
0.998795450, 0.999077737, 0.999322355, 0.999529421,
0.999698818, 0.999830604, 0.999924719, 0.999981165
};
gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/filter-i386.h 0000664 0000000 0000000 00000016321 12260363731 0020662 0 ustar 00root root 0000000 0000000 /*
* filter-i386.h -- optimized filter routines
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ---------------------------------------------------------------------- */
#ifndef _FILTER_I386_H
#define _FILTER_I386_H
/* ---------------------------------------------------------------------- */
#define __HAVE_ARCH_MAC
#define mac(a,b,size) \
(__builtin_constant_p(size) ? __mac_c((a),(b),(size)) : __mac_g((a),(b),(size)))
#include
extern inline float __mac_g(const float *a, const float *b, unsigned int size)
{
float sum = 0;
unsigned int i;
for (i = 0; i < size; i++)
sum += (*a++) * (*b++);
return sum;
}
extern inline float __mac_c(const float *a, const float *b, unsigned int size)
{
float f;
/*
* inspired from Phil Karn, KA9Q's home page
*/
switch (size) {
case 9:
asm volatile ("flds (%1);\n\t"
"fmuls (%2);\n\t"
"flds 4(%1);\n\t"
"fmuls 4(%2);\n\t"
"flds 8(%1);\n\t"
"fmuls 8(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 12(%1);\n\t"
"fmuls 12(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 16(%1);\n\t"
"fmuls 16(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 20(%1);\n\t"
"fmuls 20(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 24(%1);\n\t"
"fmuls 24(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 28(%1);\n\t"
"fmuls 28(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 32(%1);\n\t"
"fmuls 32(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"faddp;\n\t" :
"=t" (f) :
"r" (a),
"r" (b) : "memory");
return f;
case 18:
asm volatile ("flds (%1);\n\t"
"fmuls (%2);\n\t"
"flds 4(%1);\n\t"
"fmuls 4(%2);\n\t"
"flds 8(%1);\n\t"
"fmuls 8(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 12(%1);\n\t"
"fmuls 12(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 16(%1);\n\t"
"fmuls 16(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 20(%1);\n\t"
"fmuls 20(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 24(%1);\n\t"
"fmuls 24(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 28(%1);\n\t"
"fmuls 28(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 32(%1);\n\t"
"fmuls 32(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 36(%1);\n\t"
"fmuls 36(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 40(%1);\n\t"
"fmuls 40(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 44(%1);\n\t"
"fmuls 44(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 48(%1);\n\t"
"fmuls 48(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 52(%1);\n\t"
"fmuls 52(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 56(%1);\n\t"
"fmuls 56(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 60(%1);\n\t"
"fmuls 60(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 64(%1);\n\t"
"fmuls 64(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 68(%1);\n\t"
"fmuls 68(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"faddp;\n\t" :
"=t" (f) :
"r" (a),
"r" (b) : "memory");
return f;
case 24:
asm volatile ("flds (%1);\n\t"
"fmuls (%2);\n\t"
"flds 4(%1);\n\t"
"fmuls 4(%2);\n\t"
"flds 8(%1);\n\t"
"fmuls 8(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 12(%1);\n\t"
"fmuls 12(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 16(%1);\n\t"
"fmuls 16(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 20(%1);\n\t"
"fmuls 20(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 24(%1);\n\t"
"fmuls 24(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 28(%1);\n\t"
"fmuls 28(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 32(%1);\n\t"
"fmuls 32(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 36(%1);\n\t"
"fmuls 36(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 40(%1);\n\t"
"fmuls 40(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 44(%1);\n\t"
"fmuls 44(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 48(%1);\n\t"
"fmuls 48(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 52(%1);\n\t"
"fmuls 52(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 56(%1);\n\t"
"fmuls 56(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 60(%1);\n\t"
"fmuls 60(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 64(%1);\n\t"
"fmuls 64(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 68(%1);\n\t"
"fmuls 68(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 72(%1);\n\t"
"fmuls 72(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 76(%1);\n\t"
"fmuls 76(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 80(%1);\n\t"
"fmuls 80(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 84(%1);\n\t"
"fmuls 84(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 88(%1);\n\t"
"fmuls 88(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"flds 92(%1);\n\t"
"fmuls 92(%2);\n\t"
"fxch %%st(2);\n\t"
"faddp;\n\t"
"faddp;\n\t" :
"=t" (f) :
"r" (a),
"r" (b) : "memory");
return f;
default:
printf("Warning: optimize __mac_c(..., ..., %d)\n", size);
return __mac_g(a, b, size);
}
}
/* ---------------------------------------------------------------------- */
#endif /* _FILTER_I386_H */
gqrx-sdr-2.2.0.74.d97bd7/dsp/afsk1200/filter.h 0000664 0000000 0000000 00000006625 12260363731 0020201 0 ustar 00root root 0000000 0000000 /*
* filter.h -- optimized filter routines
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ---------------------------------------------------------------------- */
#ifndef _FILTER_H
#define _FILTER_H
/* ---------------------------------------------------------------------- */
#ifdef ARCH_I386
#include "filter-i386.h"
#endif /* ARCH_I386 */
/* ---------------------------------------------------------------------- */
extern inline unsigned int hweight32(unsigned int w)
__attribute__ ((unused));
extern inline unsigned int hweight16(unsigned short w)
__attribute__ ((unused));
extern inline unsigned int hweight8(unsigned char w)
__attribute__ ((unused));
extern inline unsigned int hweight32(unsigned int w)
{
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}
extern inline unsigned int hweight16(unsigned short w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
extern inline unsigned int hweight8(unsigned char w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
return (res & 0x0F) + ((res >> 4) & 0x0F);
}
extern inline unsigned int gcd(unsigned int x, unsigned int y)
__attribute__ ((unused));
extern inline unsigned int lcm(unsigned int x, unsigned int y)
__attribute__ ((unused));
extern inline unsigned int gcd(unsigned int x, unsigned int y)
{
for (;;) {
if (!x)
return y;
if (!y)
return x;
if (x > y)
x %= y;
else
y %= x;
}
}
extern inline unsigned int lcm(unsigned int x, unsigned int y)
{
return x * y / gcd(x, y);
}
/* ---------------------------------------------------------------------- */
//#ifndef __HAVE_ARCH_MAC
inline float mac(const float *a, const float *b, unsigned int size)
{
float sum = 0;
unsigned int i;
for (i = 0; i < size; i++)
sum += (*a++) * (*b++);
return sum;
}
//#endif /* __HAVE_ARCH_MAC */
inline float fsqr(float f)
{
return f*f;
}
/* ---------------------------------------------------------------------- */
#endif /* _FILTER_H */
gqrx-sdr-2.2.0.74.d97bd7/dsp/agc_impl.cpp 0000664 0000000 0000000 00000043672 12260363731 0017576 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////
// agc_impl.cpp: implementation of the CAgc class.
//
// This class implements an automatic gain function.
//
// History:
// 2010-09-15 Initial creation MSW
// 2011-03-27 Initial release
// 2011-09-24 Adapted for gqrx
//////////////////////////////////////////////////////////////////////
//==========================================================================================
// + + + This Software is released under the "Simplified BSD License" + + +
//Copyright 2010 Moe Wheatley. All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Moe Wheatley.
//==========================================================================================
#include
#include
//////////////////////////////////////////////////////////////////////
// Local Defines
//////////////////////////////////////////////////////////////////////
//signal delay line time delay in seconds.
//adjust to cover the impulse response time of filter
#define DELAY_TIMECONST .015
//Peak Detector window time delay in seconds.
#define WINDOW_TIMECONST .018
//attack time constant in seconds
//just small enough to let attackave charge up within the DELAY_TIMECONST time
#define ATTACK_RISE_TIMECONST .002
#define ATTACK_FALL_TIMECONST .005
#define DECAY_RISEFALL_RATIO .3 //ratio between rise and fall times of Decay time constants
//adjust for best action with SSB
// hang timer release decay time constant in seconds
#define RELEASE_TIMECONST .05
//limit output to about 3db of max
#define AGC_OUTSCALE 0.7
// keep max in and out the same
#define MAX_AMPLITUDE 1.0 //32767.0
#define MAX_MANUAL_AMPLITUDE 1.0 //32767.0
#define MIN_CONSTANT 3.2767e-4 // const for calc log() so that a value of 0 magnitude == -8
//corresponding to -160dB.
//K = 10^( -8 + log(32767) )
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAgc::CAgc()
{
m_AgcOn = true;
m_UseHang = false;
m_Threshold = 0;
m_ManualGain = 0;
m_SlopeFactor = 0;
m_Decay = 0;
m_SampleRate = 100.0;
}
CAgc::~CAgc()
{
}
////////////////////////////////////////////////////////////////////////////////
// Sets and calculates various AGC parameters
// "On" switches between AGC on and off.
// "Threshold" specifies AGC Knee in dB if AGC is active.( nominal range -160 to 0dB)
// "ManualGain" specifies AGC manual gain in dB if AGC is not active.(nominal range 0 to 100dB)
// "SlopeFactor" specifies dB reduction in output at knee from maximum output level(nominal range 0 to 10dB)
// "Decay" is AGC decay value in milliseconds ( nominal range 20 to 5000 milliSeconds)
// "SampleRate" is current sample rate of AGC data
////////////////////////////////////////////////////////////////////////////////
void CAgc::SetParameters(bool AgcOn, bool UseHang, int Threshold, int ManualGain,
int SlopeFactor, int Decay, double SampleRate)
{
if( (AgcOn == m_AgcOn) && (UseHang == m_UseHang) &&
(Threshold == m_Threshold) && (ManualGain == m_ManualGain) &&
(SlopeFactor == m_SlopeFactor) && (Decay == m_Decay) &&
(SampleRate == m_SampleRate) )
{
return; //just return if no parameter changed
}
//m_Mutex.lock();
m_AgcOn = AgcOn;
m_UseHang = UseHang;
m_Threshold = Threshold;
m_ManualGain = ManualGain;
m_SlopeFactor = SlopeFactor;
m_Decay = Decay;
if (m_SampleRate != SampleRate)
{ //clear out delay buffer and init some things if sample rate changes
m_SampleRate = SampleRate;
for (int i=0; i