Compare commits
6 Commits
release-1.
...
original_w
Author | SHA1 | Date | |
---|---|---|---|
4fb99c05e0 | |||
d84e672e6e | |||
a687d7f163 | |||
9f1c9a0a09 | |||
f531f3c464 | |||
d3161b6fc1 |
@ -1,7 +0,0 @@
|
||||
.git
|
||||
.gitignore
|
||||
.idea
|
||||
**/*.pyc
|
||||
**/*.swp
|
||||
black-env
|
||||
debian
|
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,29 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Installation method**
|
||||
How did you install OpenWebRX? (Raspberry Pi SD card image, Debian / Ubuntu packages, Docker image, manually?)
|
||||
|
||||
**Versions**
|
||||
What version of OpenWebRX are you running? (Check on startup, or see `owrx/version.py`. If a `-dev` version is used, ideally state the commit the issue is appearing on)
|
||||
|
||||
**Log messages**
|
||||
Are there any relevant messages relating to the bug in the output / log of OpenWebRX? (On most installations, the log should be available using the command `sudo journalctl -u openwebrx`)
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: General support request or other project-relasted question
|
||||
url: https://groups.io/g/openwebrx
|
||||
about: Request help on the community mailing list
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Before posting a new feature request, please check if a similar idea has already been listed
|
||||
* on the issue tracker
|
||||
* on the [OpenWebRX github project](https://github.com/users/jketterl/projects/1).
|
||||
|
||||
In the latter case, please only proceed if you have additional information about the feature, and please let us know that there's already a card there.
|
||||
|
||||
**Feature description**
|
||||
Please describe in plain words what functionality you'd like to see in OpenWebRX, and why you think it's useful.
|
||||
|
||||
**Target audience**
|
||||
Please let us know if you think that this feature is of particular interest for a particular group of users (e.g. hams, SWLs, DXers, ...)
|
6
.gitignore
vendored
@ -1,5 +1,3 @@
|
||||
**/*.pyc
|
||||
**/*.swp
|
||||
*.pyc
|
||||
*.swp
|
||||
tags
|
||||
.idea
|
||||
packages
|
||||
|
198
CHANGELOG.md
@ -1,198 +0,0 @@
|
||||
**1.0.0**
|
||||
- Introduced `squelch_auto_margin` config option that allows configuring the auto squelch level
|
||||
- Removed `port` configuration option; `rtltcp_compat` takes the port number with the new connectors
|
||||
- Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X 2.3) and Q65 (only avilable with
|
||||
WSJT-X 2.4)
|
||||
- Added support for demodulating M17 digital voice signals using m17-cxx-demod
|
||||
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
|
||||
- Add some basic filtering capabilities to the map
|
||||
- New arguments to the `openwebrx` command-line to facilitate the administration of users (try `openwebrx admin`)
|
||||
- Default bandwidth changes:
|
||||
- "WFM" changed to 150kHz
|
||||
- "Packet" (APRS) changed to 12.5kHz
|
||||
- Configuration rework:
|
||||
- New: fully web-based configuration interface
|
||||
- System configuration parameters have been moved to a new, separate `openwebrx.conf` file
|
||||
- Remaining parameters are now editable in the web configuration
|
||||
- Existing `config_webrx.py` files will still be read, but changes made in the web configuration will be written to
|
||||
a new storage system
|
||||
- Added upload of avatar and panorama image via web configuration
|
||||
- New devices supported:
|
||||
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
||||
- R&S devices using the EB200 or Ammos protocols
|
||||
|
||||
**0.20.3**
|
||||
- Fix a compatibility issue with python versions <= 3.6
|
||||
|
||||
**0.20.2**
|
||||
- Fix a security problem that allowed arbitrary commands to be executed on the receiver
|
||||
([See github issue #215](https://github.com/jketterl/openwebrx/issues/215))
|
||||
|
||||
**0.20.1**
|
||||
- Remove broken OSM map fallback
|
||||
|
||||
**0.20.0**
|
||||
- Added the ability to sign multiple keys in a single request, thus enabling multiple users to claim a single receiver
|
||||
on receiverbook.de
|
||||
- Fixed file descriptor leaks to prevent "too many open files" errors
|
||||
- Add new demodulator chain for FreeDV
|
||||
- Added new HD audio streaming mode along with a new WFM demodulator
|
||||
- Reworked AGC code for better results in AM, SSB and digital modes
|
||||
- Added support for demodulation of "Digital Radio Mondiale" (DRM) broadcast using the "dream" decoder.
|
||||
- New default waterfall color scheme
|
||||
- Prototype of a continuous automatic waterfall calibration mode
|
||||
- New devices supported:
|
||||
- FunCube Dongle Pro+ (`"type": "fcdpp"`)
|
||||
- Support for connections to rtl_tcp (`"type": "rtl_tcp"`)
|
||||
|
||||
**0.19.1**
|
||||
- Added ability to authenticate receivers with listing sites using "receiver id" tokens
|
||||
|
||||
**0.19.0**
|
||||
- Fix direwolf connection setup by implementing a retry loop
|
||||
- Pass direct sampling mode changes for rtl_sdr_soapy to owrx_connector
|
||||
- OSM maps instead of Google when google_maps_api_key is not set (thanks @jquagga)
|
||||
- Improved logic to pass parameters to soapy devices.
|
||||
- `rtl_sdr_soapy`: added support for `bias_tee`
|
||||
- `sdrplay`: added support for `bias_tee`, `rf_notch` and `dab_notch`
|
||||
- `airspy`: added support for `bitpack`
|
||||
- Added support for Perseus-SDR devices, (thanks @amontefusco)
|
||||
- Property System has been rewritten so that defaults on sdr behave as expected
|
||||
- Waterfall range auto-adjustment now only takes the center 80% of the spectrum into account, which should work better
|
||||
with SDRs that oversample or have rather flat filter curves towards the spectrum edges
|
||||
- Bugfix for negative network usage
|
||||
- FiFi SDR: prevent arecord from shutting down after 2GB of data has been sent
|
||||
- Added support for bias tee control on rtl_sdr devices
|
||||
- All connector driven SDRs now support `"rf_gain": "auto"` to enable AGC
|
||||
- `rtl_sdr` type now also supports the `direct_sampling` option
|
||||
- Added decoding implementation for for digimode "JS8Call"
|
||||
(requires an installation of [js8call](http://js8call.com/) and
|
||||
[the js8py library](https://github.com/jketterl/js8py))
|
||||
- Reorganization of the frontend demodulator code
|
||||
- Improve receiver load time by concatenating javascript assets
|
||||
- Docker images migrated to Debian slim images; This was necessary to allow the use of function multiversioning in
|
||||
csdr and owrx_connector to allow the images to run on a wider range of CPUs
|
||||
- Docker containers have been updated to include the SDRplay driver version 3
|
||||
- HackRF support is now based on SoapyHackRF
|
||||
- Removed sdr.hu server listing support since the site has been shut down
|
||||
- Added support for Radioberry 2 Rasbperry Pi SDR Cape
|
||||
|
||||
**0.18.0**
|
||||
- Support for SoapyRemote
|
||||
|
||||
**2020-02-08**
|
||||
- Compression, resampling and filtering in the frontend have been rewritten in javascript, sdr.js has been removed
|
||||
- Decoding of Pocsag modulation is now possible
|
||||
- Removed the 3D waterfall since it had no real application and required ~1MB of javascript code to be downloaded
|
||||
- Improved the frontend handling of the "too many users" scenario
|
||||
- PSK63 digimode is now available (same decoding pipeline as PSK31, but with adopted parameters)
|
||||
- The frequency can now be manipulated with the mousewheel, which should allow the user to tune more precise. The tuning
|
||||
step size is determined by the digit the mouse cursor is hovering over.
|
||||
- Clicking on the frequency now opens an input for direct frequency selection
|
||||
- URL hashes have been fixed and improved: They are now updated automatically, so a shared URL will include frequency
|
||||
and demodulator, which allows for improved sharing and linking.
|
||||
- New daylight scheduler for background decoding, allows profiles to be selected by local sunrise / sunset times
|
||||
- New devices supported:
|
||||
- LimeSDR (`"type": "lime_sdr"`)
|
||||
- PlutoSDR (`"type": "pluto_sdr"`)
|
||||
- RTL_SDR via Soapy (`"type": "rtl_sdr_soapy"`) on special request to allow use of the direct sampling mode
|
||||
|
||||
**2020-01-04**
|
||||
- The [owrx_connector](https://github.com/jketterl/owrx_connector) is now the default way of communicating with sdr
|
||||
devices. The old sdr types have been replaced, all `_connector` suffixes on the type must be removed!
|
||||
- The sources have been refactored, making it a lot easier to add support for other devices
|
||||
- SDR device failure handling has been improved, including user feedback
|
||||
- New devices supported:
|
||||
- FiFiSDR (`"type": "fifi_sdr"`)
|
||||
|
||||
**2019-12-15**
|
||||
- wsjt-x updated to 2.1.2
|
||||
- The rtl_tcp compatibility mode of the owrx_connector is now configurable using the `rtltcp_compat` flag
|
||||
|
||||
**2019-12-10**
|
||||
- added support for airspyhf devices (Airspy HF+ / Discovery)
|
||||
|
||||
**2019-12-05**
|
||||
- explicit device filter for soapy devices for multi-device setups
|
||||
|
||||
**2019-12-03**
|
||||
- compatibility fixes for safari browsers (ios and mac)
|
||||
|
||||
**2019-11-24**
|
||||
- There is now a new way to interface with SDR hardware, .
|
||||
They talk directly to the hardware (no rtl_sdr / rx_sdr necessary) and offer I/Q data on a socket, just like nmux
|
||||
did before. They additionally offer a control socket that allows openwebrx to control the SDR parameters directly,
|
||||
without the need for repeated restarts. This allows for quicker profile changes, and also reduces the risk of your
|
||||
SDR hardware from failing during the switchover. See `config_webrx.py` for further information and instructions.
|
||||
- Offset tuning using the `lfo_offset` has been reworked in a way that `center_freq` has to be set to the frequency you
|
||||
actually want to listen to. If you're using an `lfo_offset` already, you will probably need to change its sign.
|
||||
- `initial_squelch_level` can now be set on each profile.
|
||||
- As usual, plenty of fixes and improvements.
|
||||
|
||||
**2019-10-27**
|
||||
- Part of the frontend code has been reworked
|
||||
- Audio buffer minimums have been completely stripped. As a result, you should get better latency. Unfortunately,
|
||||
this also means there will be some skipping when audio starts.
|
||||
- Now also supports AudioWorklets (for those browser that have it). The Raspberry Pi image has been updated to include
|
||||
https due to the SecureContext requirement.
|
||||
- Mousewheel controls for the receiver sliders
|
||||
- Error handling for failed SDR devices
|
||||
|
||||
**2019-09-29**
|
||||
- One of the most-requested features is finally coming to OpenWebRX: Bookmarks (sometimes also referred to as labels).
|
||||
There's two kinds of bookmarks available:
|
||||
- Serverside bookmarks that are set up by the receiver administrator. Check the file `bookmarks.json` for examples!
|
||||
- Clientside bookmarks which every user can store for themselves. They are stored in the browser's localStorage.
|
||||
- Some more bugs in the websocket handling have been fixed.
|
||||
|
||||
**2019-09-25**
|
||||
- Automatic reporting of spots to [pskreporter](https://pskreporter.info/) is now possible. Please have a look at the
|
||||
configuration on how to set it up.
|
||||
- Websocket communication has been overhauled in large parts. It should now be more reliable, and failing connections
|
||||
should now have no impact on other users.
|
||||
- Profile scheduling allows to set up band-hopping if you are running background services.
|
||||
- APRS now has the ability to show symbols on the map, if a corresponding symbol set has been installed. Check the
|
||||
config!
|
||||
- Debug logging has been disabled in a handful of modules, expect vastly reduced output on the shell.
|
||||
|
||||
**2019-09-13**
|
||||
- New set of APRS-related features
|
||||
- Decode Packet transmissions using [direwolf](https://github.com/wb2osz/direwolf) (1k2 only for now)
|
||||
- APRS packets are mostly decoded and shown both in a new panel and on the map
|
||||
- APRS is also available as a background service
|
||||
- direwolfs I-gate functionality can be enabled, which allows your receiver to work as a receive-only I-gate for the
|
||||
APRS network in the background
|
||||
- Demodulation for background services has been optimized to use less total bandwidth, saving CPU
|
||||
- More metrics have been added; they can be used together with collectd and its curl_json plugin for now, with some
|
||||
limitations.
|
||||
|
||||
**2019-07-21**
|
||||
- Latest Features:
|
||||
- More WSJT-X modes have been added, including the new FT4 mode
|
||||
- I started adding a bandplan feature, the first thing visible is the "dial" indicator that brings you right to the
|
||||
dial frequency for digital modes
|
||||
- fixed some bugs in the websocket communication which broke the map
|
||||
|
||||
**2019-07-13**
|
||||
- Latest Features:
|
||||
- FT8 Integration (using wsjt-x demodulators)
|
||||
- New Map Feature that shows both decoded grid squares from FT8 and Locations decoded from YSF digital voice
|
||||
- New Feature report that will show what functionality is available
|
||||
- There's a new Raspbian SD Card image available (see below)
|
||||
|
||||
**2019-06-30**
|
||||
- I have done some major rework on the openwebrx core, and I am planning to continue adding more features in the near
|
||||
future. Please check this place for updates.
|
||||
- My work has not been accepted into the upstream repository, so you will need to chose between my fork and the official
|
||||
version.
|
||||
- I have enabled the issue tracker on this project, so feel free to file bugs or suggest enhancements there!
|
||||
- This version sports the following new and amazing features:
|
||||
- Support of multiple SDR devices simultaneously
|
||||
- Support for multiple profiles per SDR that allow the user to listen to different frequencies
|
||||
- Support for digital voice decoding
|
||||
- Feature detection that will disable functionality when dependencies are not available (if you're missing the digital
|
||||
buttons, this is probably why)
|
||||
- Raspbian SD Card Images and Docker builds available (see below)
|
||||
- I am currently working on the feature set for a stable release, but you are more than welcome to test development
|
||||
versions!
|
15
CONTRIBUTING.md
Normal file
@ -0,0 +1,15 @@
|
||||
First of all, thank you for taking the time to contribute to this project!
|
||||
|
||||
Before I can accept your contributions, I need a signed copy of the Individual Contributor License Agreement (ICLA) from you, which is available <a href="ICLA.txt">here</a>.
|
||||
|
||||
The ICLA is needed because it will allow me to dual license the OpenWebRX project under AGPL and a commercial license.
|
||||
I will also apply dual licensing to csdr, but only those parts that are original work (e.g. without the parts enabled by `-DUSE_IMA_ADPCM`; code taken from other projects is clearly separable).
|
||||
|
||||
However, even if there is commercial interest in the projects, I promise to keep them as open as possible, keeping my original intention to provide an open-source web-based SDR receiver software to the amateur radio operators and SDR enthusiasts.
|
||||
|
||||
This contributor agreement is based on the one of Apache Software Foundation, with some modifications. (You can review differences <a href="https://gist.github.com/ha7ilm/9e981006d24659e336c7/revisions">here</a>).
|
||||
When you contribute for the first time, I will send you the ICLA. Replying with only the information requested and the text "I Agree" is sufficient.
|
||||
|
||||
Thanks,
|
||||
|
||||
Andras, HA7ILM
|
5
CONTRIBUTORS
Normal file
@ -0,0 +1,5 @@
|
||||
This is a list of the great people who contributed code to the OpenWebRX repository. (Names are sorted alphabetically.)
|
||||
|
||||
Gnoxter <gnoxter@linuxlounge.net>
|
||||
John Seamons, ZL/KF6VO <jks@jks.com>
|
||||
|
128
ICLA.txt
Normal file
@ -0,0 +1,128 @@
|
||||
Individual Contributor License Agreement ("Agreement")
|
||||
|
||||
In order to clarify the intellectual property license granted
|
||||
with Contributions from any person or entity, Retzler András
|
||||
(hereinafter referred to as "Project Owner") must have a
|
||||
Contributor License Agreement ("CLA") on file that has
|
||||
been signed by each Contributor, indicating agreement to the license
|
||||
terms below. This license is for your protection as a Contributor as
|
||||
well as the protection of the Project Owner; it does not change your
|
||||
rights to use your own Contributions for any other purpose.
|
||||
Please read this document carefully before signing and keep a copy
|
||||
for your records.
|
||||
|
||||
Full name: ______________________________________________________
|
||||
|
||||
(optional) Public name: _________________________________________
|
||||
|
||||
Mailing Address: ________________________________________________
|
||||
|
||||
________________________________________________
|
||||
|
||||
Country: ______________________________________________________
|
||||
|
||||
(optional) Telephone: ___________________________________________
|
||||
|
||||
E-Mail: ______________________________________________________
|
||||
|
||||
You accept and agree to the following terms and conditions for Your
|
||||
present and future Contributions submitted to the Project Owner.
|
||||
|
||||
Except for the license granted herein to the Project Owner and recipients
|
||||
of software distributed by the Project Owner, You reserve all right, title,
|
||||
and interest in and to Your Contributions.
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"You" (or "Your") shall mean the copyright owner or legal entity
|
||||
authorized by the copyright owner that is making this Agreement
|
||||
with the Project Owner. For legal entities, the entity making a
|
||||
Contribution and all other entities that control, are controlled
|
||||
by, or are under common control with that entity are considered to
|
||||
be a single Contributor. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"Contribution" shall mean any original work of authorship,
|
||||
including any modifications or additions to an existing work, that
|
||||
is intentionally submitted by You to the Project Owner for inclusion
|
||||
in, or documentation of, any of the products owned or managed by
|
||||
the Project Owner (the "Work"). For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written
|
||||
communication sent to the Project Owner or its representatives,
|
||||
including but not limited to communication on electronic mailing
|
||||
lists, source code control systems, and issue tracking systems that
|
||||
are managed by, or on behalf of, the Project Owner for the purpose of
|
||||
discussing and improving the Work, but excluding communication that
|
||||
is conspicuously marked or otherwise designated in writing by You
|
||||
as "Not a Contribution."
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this Agreement, You hereby grant to the Project Owner and to
|
||||
recipients of software distributed by the Project Owner a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare derivative works of,
|
||||
publicly display, publicly perform, sublicense, and distribute Your
|
||||
Contributions and such derivative works.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this Agreement, You hereby grant to the Project Owner and to
|
||||
recipients of software distributed by the Project Owner a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the
|
||||
Work, where such license applies only to those patent claims
|
||||
licensable by You that are necessarily infringed by Your
|
||||
Contribution(s) alone or by combination of Your Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If any
|
||||
entity institutes patent litigation against You or any other entity
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that your Contribution, or the Work to which you have contributed,
|
||||
constitutes direct or contributory patent infringement, then any
|
||||
patent licenses granted to that entity under this Agreement for
|
||||
that Contribution or Work shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
||||
4. You represent that you are legally entitled to grant the above
|
||||
license. If your employer(s) has rights to intellectual property
|
||||
that you create that includes your Contributions, you represent
|
||||
that you have received permission to make Contributions on behalf
|
||||
of that employer, that your employer has waived such rights for
|
||||
your Contributions to the Project Owner, or that your employer has
|
||||
executed a separate Corporate CLA with the Project Owner.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original
|
||||
creation (see section 7 for submissions on behalf of others). You
|
||||
represent that Your Contribution submissions include complete
|
||||
details of any third-party license or other restriction (including,
|
||||
but not limited to, related patents and trademarks) of which you
|
||||
are personally aware and which are associated with any part of Your
|
||||
Contributions.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions,
|
||||
except to the extent You desire to provide support. You may provide
|
||||
support for free, for a fee, or not at all. Unless required by
|
||||
applicable law or agreed to in writing, You provide Your
|
||||
Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties or conditions of TITLE, NON-
|
||||
INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. Should You wish to submit work that is not Your original creation,
|
||||
You may submit it to the Project Owner separately from any
|
||||
Contribution, identifying the complete details of its source and of
|
||||
any license or other restriction (including, but not limited to,
|
||||
related patents, trademarks, and license agreements) of which you
|
||||
are personally aware, and conspicuously marking the work as
|
||||
"Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify the Project Owner of any facts or circumstances of
|
||||
which you become aware that would make these representations
|
||||
inaccurate in any respect.
|
||||
|
||||
Please sign: __________________________________ Date: ________________
|
||||
|
||||
Text derived from the Apache Individual Contributor License Agreement
|
||||
("Agreement") V2.0, available at http://apache.org/licenses/icla.txt
|
122
README.md
@ -1,48 +1,94 @@
|
||||
OpenWebRX
|
||||
=========
|
||||
# OpenWebRX
|
||||
|
||||
OpenWebRX is a multi-user SDR receiver software with a web interface.
|
||||
|
||||

|
||||
----
|
||||
|
||||
### ⚠️ From 2019-12-29 OpenWebRX development is discontinued. ⚠️
|
||||
|
||||
I'm would like to say a big thanks to everyone who supported me during this project, including those who contributed either code or donations. It has been a very fruitful 6 years, but now it's time to move on to other projects. See also my [blog](https://blog.sdr.hu) about that.
|
||||
|
||||
(@simonyiszk, please keep this GitHub repo for historic purposes.)
|
||||
|
||||
Know limitations of the last version:
|
||||
|
||||
- Python 2.7, a main dependency of the project, will be not be officially maintained from 1 January 2020. By time, probably it will not be secure to use this version on public servers, unless someone still provides security patches for Python 2.
|
||||
- Some specific parts of the DSP code could be improved for better SNR.
|
||||
|
||||
Even though these limitations are probably acceptable in an amateur radio project, I would not build critical infrastructure on it.
|
||||
|
||||
For commercial inquiries (e.g. if someone wants me to develop an improved version without these limitations), I'm still open, [drop me an e-mail](mailto:randras@sdr.hu).
|
||||
|
||||
----
|
||||
|
||||
[:floppy_disk: Setup guide for Ubuntu](http://blog.sdr.hu/2015/06/30/quick-setup-openwebrx.html) | [:blue_book: Knowledge base on the Wiki](https://github.com/simonyiszk/openwebrx/wiki/) | [:earth_americas: Receivers on SDR.hu](http://sdr.hu/)
|
||||
|
||||

|
||||
|
||||
It has the following features:
|
||||
|
||||
- [csdr](https://github.com/jketterl/csdr) based demodulators (AM/FM/SSB/CW/BPSK31/BPSK63)
|
||||
- filter passband can be set from GUI
|
||||
- it extensively uses HTML5 features like WebSocket, Web Audio API, and Canvas
|
||||
- it works in Google Chrome, Chromium and Mozilla Firefox
|
||||
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
|
||||
- Multiple SDR devices can be used simultaneously
|
||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
|
||||
- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
|
||||
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||
FST4W)
|
||||
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
||||
- [JS8Call](http://js8call.com/) support
|
||||
- [DRM](https://github.com/jketterl/openwebrx/wiki/DRM-demodulator-notes) support
|
||||
- [FreeDV](https://github.com/jketterl/openwebrx/wiki/FreeDV-demodulator-notes) support
|
||||
- M17 support based on [m17-cxx-demod](https://github.com/mobilinkd/m17-cxx-demod)
|
||||
- <a href="https://github.com/simonyiszk/csdr">csdr</a> based demodulators (AM/FM/SSB/CW/BPSK31),
|
||||
- filter passband can be set from GUI,
|
||||
- waterfall display can be shifted back in time,
|
||||
- it extensively uses HTML5 features like WebSocket, Web Audio API, and <canvas>,
|
||||
- it works in Google Chrome, Chromium (above version 37) and Mozilla Firefox (above version 28),
|
||||
- currently supports RTL-SDR, HackRF, SDRplay, AirSpy and many other devices, see the <a href="https://github.com/simonyiszk/openwebrx/wiki/">OpenWebRX Wiki</a>,
|
||||
- it has a 3D waterfall display:
|
||||
|
||||

|
||||
|
||||
**News (2015-08-18)**
|
||||
- My BSc. thesis written on OpenWebRX is <a href="https://sdr.hu/static/bsc-thesis.pdf">available here.</a>
|
||||
- Several bugs were fixed to improve reliability and stability.
|
||||
- OpenWebRX now supports compression of audio and waterfall stream, so the required network uplink bandwidth has been decreased from 2 Mbit/s to about 200 kbit/s per client! (Measured with the default settings. It is also dependent on `fft_size`.)
|
||||
- OpenWebRX now uses <a href="https://github.com/simonyiszk/csdr#sdrjs">sdr.js</a> (*libcsdr* compiled to JavaScript) for some client-side DSP tasks.
|
||||
- Receivers can now be listed on <a href="http://sdr.hu/">SDR.hu</a>.
|
||||
- License for OpenWebRX is now Affero GPL v3.
|
||||
|
||||
**News (2016-02-14)**
|
||||
- The DDC in *csdr* has been manually optimized for ARM NEON, so it runs around 3 times faster on the Raspberry Pi 2 than before.
|
||||
- Also we use *ncat* instead of *rtl_mus*, and it is 3 times faster in some cases.
|
||||
- OpenWebRX now supports URLs like: `http://localhost:8073/#freq=145555000,mod=usb`
|
||||
- UI improvements were made, thanks to John Seamons and Gnoxter.
|
||||
|
||||
**News (2017-04-04)**
|
||||
- *ncat* has been replaced with a custom implementation called *nmux* due to a bug that caused regular crashes on some machines. The *nmux* tool is part of the *csdr* package.
|
||||
- Most consumer SDR devices are supported via <a href="https://github.com/rxseger/rx_tools">rx_tools</a>, see the <a href="https://github.com/simonyiszk/openwebrx/wiki/Using-rx_tools-with-OpenWebRX">OpenWebRX Wiki</a> on that.
|
||||
|
||||
**News (2017-07-12)**
|
||||
- OpenWebRX now has a BPSK31 demodulator and a 3D waterfall display.
|
||||
|
||||
> When upgrading OpenWebRX, please make sure that you also upgrade *csdr*!
|
||||
|
||||
## OpenWebRX servers on SDR.hu
|
||||
|
||||
[SDR.hu](http://sdr.hu) is a site which lists the active, public OpenWebRX servers. Your receiver [can also be part of it](http://sdr.hu/openwebrx), if you want.
|
||||
|
||||

|
||||
|
||||
## Setup
|
||||
|
||||
The following methods of setting up a receiver are currently available:
|
||||
OpenWebRX currently requires Linux and python 2.7 to run.
|
||||
|
||||
- Raspberry Pi SD card images
|
||||
- Debian repository
|
||||
- Docker images
|
||||
- Manual installation
|
||||
First you will need to install the dependencies:
|
||||
|
||||
Please checkout the [setup guide on the wiki](https://github.com/jketterl/openwebrx/wiki/Setup-Guide) for more details
|
||||
on the respective methods.
|
||||
- <a href="https://github.com/simonyiszk/csdr">libcsdr</a>
|
||||
- <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl-sdr</a>
|
||||
|
||||
## Community
|
||||
After cloning this repository and connecting an RTL-SDR dongle to your computer, you can run the server:
|
||||
|
||||
If you have trouble setting up or configuring your receiver, you have some great idea you want to see implemented, or
|
||||
you just generally want to have some OpenWebRX-related chat, come visit us over on
|
||||
[our groups.io group](https://groups.io/g/openwebrx).
|
||||
python openwebrx.py
|
||||
|
||||
If you want to hang out, chat, or get in touch directly with the developers, receiver operators or users, feel free to
|
||||
drop by in [our Discord server](https://discord.gg/gnE9hPz).
|
||||
You can now open the GUI at <a href="http://localhost:8073">http://localhost:8073</a>.
|
||||
|
||||
Please note that the server is also listening on the following ports (on localhost only):
|
||||
|
||||
- port 4951 for the multi-user I/Q server.
|
||||
|
||||
Now the next step is to customize the parameters of your server in `config_webrx.py`.
|
||||
|
||||
Actually, if you do something cool with OpenWebRX, please drop me a mail:
|
||||
*Andras Retzler, HA7ILM <randras@sdr.hu>*
|
||||
|
||||
## Usage tips
|
||||
|
||||
@ -52,10 +98,16 @@ The filter envelope can be dragged at its ends and moved around to set the passb
|
||||
|
||||
However, if you hold down the shift key, you can drag the center line (BFO) or the whole passband (PBS).
|
||||
|
||||
## Setup tips
|
||||
|
||||
If you have any problems installing OpenWebRX, you should check out the <a href="https://github.com/simonyiszk/openwebrx/wiki">Wiki</a> about it, which has a page on the <a href="https://github.com/simonyiszk/openwebrx/wiki/Common-problems-and-their-solutions">common problems and their solutions</a>.
|
||||
|
||||
Sometimes the actual error message is not at the end of the terminal output, you may have to look at the whole output to find it.
|
||||
|
||||
If you want to run OpenWebRX on a remote server instead of *localhost*, do not forget to set *server_hostname* in `config_webrx.py`.
|
||||
|
||||
## Licensing
|
||||
|
||||
OpenWebRX is available under Affero GPL v3 license
|
||||
([summary](https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0))).
|
||||
OpenWebRX is available under Affero GPL v3 license (<a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">summary</a>).
|
||||
|
||||
OpenWebRX is also available under a commercial license on request. Please contact me at the address
|
||||
*<randras@sdr.hu>* for licensing options.
|
||||
OpenWebRX is also available under a commercial license on request. Please contact me at the address *<randras@sdr.hu>* for licensing options.
|
||||
|
367
bands.json
@ -1,367 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "2190m",
|
||||
"lower_bound": 135700,
|
||||
"upper_bound": 137800,
|
||||
"frequencies": {
|
||||
"fst4": 136000,
|
||||
"fst4w": 136000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "630m",
|
||||
"lower_bound": 472000,
|
||||
"upper_bound": 479000,
|
||||
"frequencies": {
|
||||
"fst4": 474200,
|
||||
"fst4w": 474200
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "160m",
|
||||
"lower_bound": 1810000,
|
||||
"upper_bound": 2000000,
|
||||
"frequencies": {
|
||||
"bpsk31": 1838000,
|
||||
"ft8": 1840000,
|
||||
"wspr": 1836600,
|
||||
"jt65": 1838000,
|
||||
"jt9": 1839000,
|
||||
"js8": 1842000,
|
||||
"fst4": 1839000,
|
||||
"fst4w": 1836800
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "80m",
|
||||
"lower_bound": 3500000,
|
||||
"upper_bound": 3800000,
|
||||
"frequencies": {
|
||||
"bpsk31": 3580000,
|
||||
"ft8": 3573000,
|
||||
"wspr": 3592600,
|
||||
"jt65": 3570000,
|
||||
"jt9": 3572000,
|
||||
"ft4": [3568000, 3575000],
|
||||
"js8": 3578000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "60m",
|
||||
"lower_bound": 5351500,
|
||||
"upper_bound": 5366500,
|
||||
"frequencies": {
|
||||
"ft8": 5357000,
|
||||
"wspr": 5364700
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "40m",
|
||||
"lower_bound": 7000000,
|
||||
"upper_bound": 7200000,
|
||||
"frequencies": {
|
||||
"bpsk31": 7040000,
|
||||
"ft8": 7074000,
|
||||
"wspr": 7038600,
|
||||
"jt65": 7076000,
|
||||
"jt9": 7078000,
|
||||
"ft4": 7047500,
|
||||
"js8": 7078000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "30m",
|
||||
"lower_bound": 10100000,
|
||||
"upper_bound": 10150000,
|
||||
"frequencies": {
|
||||
"bpsk31": 10141000,
|
||||
"ft8": 10136000,
|
||||
"wspr": 10138700,
|
||||
"jt65": 10138000,
|
||||
"jt9": 10140000,
|
||||
"ft4": 10140000,
|
||||
"js8": 10130000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "20m",
|
||||
"lower_bound": 14000000,
|
||||
"upper_bound": 14350000,
|
||||
"frequencies": {
|
||||
"bpsk31": 14070000,
|
||||
"ft8": 14074000,
|
||||
"wspr": 14095600,
|
||||
"jt65": 14076000,
|
||||
"jt9": 14078000,
|
||||
"ft4": 14080000,
|
||||
"js8": 14078000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "17m",
|
||||
"lower_bound": 18068000,
|
||||
"upper_bound": 18168000,
|
||||
"frequencies": {
|
||||
"bpsk31": 18098000,
|
||||
"ft8": 18100000,
|
||||
"wspr": 18104600,
|
||||
"jt65": 18102000,
|
||||
"jt9": 18104000,
|
||||
"ft4": 18104000,
|
||||
"js8": 18104000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "15m",
|
||||
"lower_bound": 21000000,
|
||||
"upper_bound": 21450000,
|
||||
"frequencies": {
|
||||
"bpsk31": 21070000,
|
||||
"ft8": 21074000,
|
||||
"wspr": 21094600,
|
||||
"jt65": 21076000,
|
||||
"jt9": 21078000,
|
||||
"ft4": 21140000,
|
||||
"js8": 21078000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "12m",
|
||||
"lower_bound": 24890000,
|
||||
"upper_bound": 24990000,
|
||||
"frequencies": {
|
||||
"bpsk31": 24920000,
|
||||
"ft8": 24915000,
|
||||
"wspr": 24924600,
|
||||
"jt65": 24917000,
|
||||
"jt9": 24919000,
|
||||
"ft4": 24919000,
|
||||
"js8": 24922000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "10m",
|
||||
"lower_bound": 28000000,
|
||||
"upper_bound": 29700000,
|
||||
"frequencies": {
|
||||
"bpsk31": [28070000, 28120000],
|
||||
"ft8": 28074000,
|
||||
"wspr": 28124600,
|
||||
"jt65": 28076000,
|
||||
"jt9": 28078000,
|
||||
"ft4": 28180000,
|
||||
"js8": 28078000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "6m",
|
||||
"lower_bound": 50030000,
|
||||
"upper_bound": 51000000,
|
||||
"frequencies": {
|
||||
"bpsk31": 50305000,
|
||||
"ft8": 50313000,
|
||||
"wspr": 50293000,
|
||||
"jt65": 50310000,
|
||||
"jt9": 50312000,
|
||||
"ft4": 50318000,
|
||||
"js8": 50318000,
|
||||
"q65": [50211000, 50275000]
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "4m",
|
||||
"lower_bound": 70150000,
|
||||
"upper_bound": 70200000,
|
||||
"frequencies": {
|
||||
"wspr": 70091000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "2m",
|
||||
"lower_bound": 144000000,
|
||||
"upper_bound": 146000000,
|
||||
"frequencies": {
|
||||
"wspr": 144489000,
|
||||
"ft8": 144174000,
|
||||
"ft4": 144170000,
|
||||
"jt65": 144120000,
|
||||
"packet": 144800000,
|
||||
"q65": 144116000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "70cm",
|
||||
"lower_bound": 430000000,
|
||||
"upper_bound": 440000000,
|
||||
"frequencies": {
|
||||
"pocsag": 439987500,
|
||||
"q65": 432065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "23cm",
|
||||
"lower_bound": 1240000000,
|
||||
"upper_bound": 1300000000,
|
||||
"frequencies": {
|
||||
"q65": 1296065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "13cm",
|
||||
"lower_bound": 2320000000,
|
||||
"upper_bound": 2450000000,
|
||||
"frequencies": {
|
||||
"q65": [2301065000, 2304065000, 2320065000]
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "9cm",
|
||||
"lower_bound": 3400000000,
|
||||
"upper_bound": 3475000000,
|
||||
"frequencies": {
|
||||
"q65": 3400065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "6cm",
|
||||
"lower_bound": 5650000000,
|
||||
"upper_bound": 5850000000,
|
||||
"frequencies": {
|
||||
"q65": 5760200000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "3cm",
|
||||
"lower_bound": 10000000000,
|
||||
"upper_bound": 10500000000,
|
||||
"frequencies": {
|
||||
"q65": 10368200000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "120m Broadcast",
|
||||
"lower_bound": 2300000,
|
||||
"upper_bound": 2495000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "90m Broadcast",
|
||||
"lower_bound": 3200000,
|
||||
"upper_bound": 3400000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "75m Broadcast",
|
||||
"lower_bound": 3900000,
|
||||
"upper_bound": 4000000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "60m Broadcast",
|
||||
"lower_bound": 4750000,
|
||||
"upper_bound": 4995000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "49m Broadcast",
|
||||
"lower_bound": 5900000,
|
||||
"upper_bound": 6200000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "41m Broadcast",
|
||||
"lower_bound": 7200000,
|
||||
"upper_bound": 7450000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "31m Broadcast",
|
||||
"lower_bound": 9400000,
|
||||
"upper_bound": 9900000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "25m Broadcast",
|
||||
"lower_bound": 11600000,
|
||||
"upper_bound": 12100000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "22m Broadcast",
|
||||
"lower_bound": 13570000,
|
||||
"upper_bound": 13870000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "19m Broadcast",
|
||||
"lower_bound": 15100000,
|
||||
"upper_bound": 15830000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "16m Broadcast",
|
||||
"lower_bound": 17480000,
|
||||
"upper_bound": 17900000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "15m Broadcast",
|
||||
"lower_bound": 18900000,
|
||||
"upper_bound": 19020000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "13m Broadcast",
|
||||
"lower_bound": 21450000,
|
||||
"upper_bound": 21850000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "11m Broadcast",
|
||||
"lower_bound": 25670000,
|
||||
"upper_bound": 26100000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "FM Broadcast",
|
||||
"lower_bound": 87500000,
|
||||
"upper_bound": 108000000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "11m CB",
|
||||
"lower_bound": 26965000,
|
||||
"upper_bound": 27405000,
|
||||
"frequencies": {
|
||||
"js8": 27245000
|
||||
},
|
||||
"tags": ["public"]
|
||||
},
|
||||
{
|
||||
"name": "PMR446",
|
||||
"lower_bound": 446000000,
|
||||
"upper_bound": 446200000,
|
||||
"tags": ["public"]
|
||||
}
|
||||
]
|
463
config_webrx.py
@ -6,7 +6,6 @@ config_webrx: configuration options for OpenWebRX
|
||||
This file is part of OpenWebRX,
|
||||
an open-source SDR receiver software with a web UI.
|
||||
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
|
||||
Copyright (c) 2019-2021 by Jakob Ketterl <dd5jfk@darc.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@ -32,86 +31,62 @@ config_webrx: configuration options for OpenWebRX
|
||||
and use them for running your web service with OpenWebRX.)
|
||||
"""
|
||||
|
||||
"""
|
||||
DEPRECATION notice
|
||||
|
||||
As of OpenWebRX 0.21, the configuration system has been completely overhauled.
|
||||
The configuration of OpenWebRX should now be done in the new web-based
|
||||
configuration interface exclusively.
|
||||
|
||||
Existing configurations can still be used, but their values will be migrated
|
||||
to the new storage infrastructure as soon as the web configuration is used to
|
||||
edit them.
|
||||
|
||||
The new configuration storage is not intended to be edited manually.
|
||||
"""
|
||||
|
||||
# configuration version. please only modify if you're able to perform the associated migration steps.
|
||||
version = 7
|
||||
|
||||
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
|
||||
# https://github.com/simonyiszk/openwebrx/wiki
|
||||
|
||||
# ==== Server settings ====
|
||||
#max_clients = 20
|
||||
web_port=8073
|
||||
server_hostname="localhost" # If this contains an incorrect value, the web UI may freeze on load (it can't open websocket)
|
||||
max_clients=20
|
||||
|
||||
# ==== Web GUI configuration ====
|
||||
#receiver_name = "[Callsign]"
|
||||
#receiver_location = "Budapest, Hungary"
|
||||
#receiver_asl = 200
|
||||
#receiver_admin = "example@example.com"
|
||||
#receiver_gps = {"lat": 47.000000, "lon": 19.000000}
|
||||
#photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
|
||||
# photo_desc allows you to put pretty much any HTML you like into the receiver description.
|
||||
# The lines below should give you some examples of what's possible.
|
||||
#photo_desc = """
|
||||
#You can add your own background photo and receiver information.<br />
|
||||
#Receiver is operated by: <a href="mailto:openwebrx@localhost" target="_blank">Receiver Operator</a><br/>
|
||||
#Device: Receiver Device<br />
|
||||
#Antenna: Receiver Antenna<br />
|
||||
#Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||
#"""
|
||||
receiver_name="[Callsign]"
|
||||
receiver_location="Budapest, Hungary"
|
||||
receiver_qra="JN97ML"
|
||||
receiver_asl=200
|
||||
receiver_ant="Longwire"
|
||||
receiver_device="RTL-SDR"
|
||||
receiver_admin="example@example.com"
|
||||
receiver_gps=(47.000000,19.000000)
|
||||
photo_height=350
|
||||
photo_title="Panorama of Budapest from Schönherz Zoltán Dormitory"
|
||||
photo_desc="""
|
||||
You can add your own background photo and receiver information.<br />
|
||||
Receiver is operated by: <a href="mailto:%[RX_ADMIN]">%[RX_ADMIN]</a><br/>
|
||||
Device: %[RX_DEVICE]<br />
|
||||
Antenna: %[RX_ANT]<br />
|
||||
Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||
"""
|
||||
|
||||
# ==== Public receiver listings ====
|
||||
# You can publish your receiver on online receiver directories, like https://www.receiverbook.de
|
||||
# You will receive a receiver key from the directory that will authenticate you as the operator of this receiver.
|
||||
# Please note that you not share your receiver keys publicly since anyone that obtains your receiver key can take over
|
||||
# your public listing.
|
||||
# Your receiver keys should be placed into this array:
|
||||
#receiver_keys = []
|
||||
# If you list your receiver on multiple sites, you can place all your keys into the array above, or you can append
|
||||
# keys to the arraylike this:
|
||||
# receiver_keys += ["my-receiver-key"]
|
||||
|
||||
# If you're not sure, simply copy & paste the code you received from your listing site below this line:
|
||||
# ==== sdr.hu listing ====
|
||||
# If you want your ham receiver to be listed publicly on sdr.hu, then take the following steps:
|
||||
# 1. Register at: http://sdr.hu/register
|
||||
# 2. You will get an unique key by email. Copy it and paste here:
|
||||
sdrhu_key = ""
|
||||
# 3. Set this setting to True to enable listing:
|
||||
sdrhu_public_listing = False
|
||||
|
||||
# ==== DSP/RX settings ====
|
||||
#fft_fps = 9
|
||||
#fft_size = 4096 # Should be power of 2
|
||||
#fft_voverlap_factor = (
|
||||
# 0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
|
||||
#)
|
||||
fft_fps=9
|
||||
fft_size=4096 #Should be power of 2
|
||||
fft_voverlap_factor=0.3 #If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
|
||||
|
||||
#audio_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
#fft_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
# samp_rate = 250000
|
||||
samp_rate = 2400000
|
||||
center_freq = 144250000
|
||||
rf_gain = 5 #in dB. For an RTL-SDR, rf_gain=0 will set the tuner to auto gain mode, else it will be in manual gain mode.
|
||||
ppm = 0
|
||||
|
||||
# Tau setting for WFM (broadcast FM) deemphasis\
|
||||
# Quote from wikipedia https://en.wikipedia.org/wiki/FM_broadcasting#Pre-emphasis_and_de-emphasis
|
||||
# "In most of the world a 50 µs time constant is used. In the Americas and South Korea, 75 µs is used"
|
||||
# Enable one of the following lines, depending on your location:
|
||||
# wfm_deemphasis_tau = 75e-6 # for US and South Korea
|
||||
#wfm_deemphasis_tau = 50e-6 # for the rest of the world
|
||||
audio_compression="adpcm" #valid values: "adpcm", "none"
|
||||
fft_compression="adpcm" #valid values: "adpcm", "none"
|
||||
|
||||
#digimodes_fft_size = 2048
|
||||
digimodes_enable=True #Decoding digimodes come with higher CPU usage.
|
||||
digimodes_fft_size=1024
|
||||
|
||||
# determines the quality, and thus the cpu usage, for the ambe codec used by digital voice modes
|
||||
# if you're running on a Raspi (up to 3B+) you'll want to leave this on 1
|
||||
#digital_voice_unvoiced_quality = 1
|
||||
# enables lookup of DMR ids using the radioid api
|
||||
#digital_voice_dmr_id_lookup = True
|
||||
start_rtl_thread=True
|
||||
|
||||
"""
|
||||
Note: if you experience audio underruns while CPU usage is 100%, you can:
|
||||
Note: if you experience audio underruns while CPU usage is 100%, you can:
|
||||
- decrease `samp_rate`,
|
||||
- set `fft_voverlap_factor` to 0,
|
||||
- decrease `fft_fps` and `fft_size`,
|
||||
@ -121,269 +96,121 @@ Note: if you experience audio underruns while CPU usage is 100%, you can:
|
||||
# ==== I/Q sources ====
|
||||
# (Uncomment the appropriate by removing # characters at the beginning of the corresponding lines.)
|
||||
|
||||
###############################################################################
|
||||
# Is my SDR hardware supported? #
|
||||
# Check here: https://github.com/jketterl/openwebrx/wiki/Supported-Hardware #
|
||||
###############################################################################
|
||||
#################################################################################################
|
||||
# Is my SDR hardware supported? #
|
||||
# Check here: https://github.com/simonyiszk/openwebrx/wiki#guides-for-receiver-hardware-support #
|
||||
#################################################################################################
|
||||
|
||||
# Currently supported types of sdr receivers:
|
||||
# "rtl_sdr", "rtl_sdr_soapy", "sdrplay", "hackrf", "airspy", "airspyhf", "fifi_sdr",
|
||||
# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "uhd",
|
||||
# "radioberry", "fcdpp", "rtl_tcp", "sddc", "runds"
|
||||
# You can use other SDR hardware as well, by giving your own command that outputs the I/Q samples... Some examples of configuration are available here (default is RTL-SDR):
|
||||
|
||||
# For more details on specific types, please checkout the wiki:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices
|
||||
# >> RTL-SDR via rtl_sdr
|
||||
start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm)
|
||||
format_conversion="csdr convert_u8_f"
|
||||
|
||||
#sdrs = {
|
||||
# "rtlsdr": {
|
||||
# "name": "RTL-SDR USB Stick",
|
||||
# "type": "rtl_sdr",
|
||||
# "ppm": 0,
|
||||
# # you can change this if you use an upconverter. formula is:
|
||||
# # center_freq + lfo_offset = actual frequency on the sdr
|
||||
# # "lfo_offset": 0,
|
||||
# "profiles": {
|
||||
# "70cm": {
|
||||
# "name": "70cm Relais",
|
||||
# "center_freq": 438800000,
|
||||
# "rf_gain": 29,
|
||||
# "samp_rate": 2400000,
|
||||
# "start_freq": 439275000,
|
||||
# "start_mod": "nfm",
|
||||
# },
|
||||
# "2m": {
|
||||
# "name": "2m komplett",
|
||||
# "center_freq": 145000000,
|
||||
# "rf_gain": 29,
|
||||
# "samp_rate": 2048000,
|
||||
# "start_freq": 145725000,
|
||||
# "start_mod": "nfm",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# "airspy": {
|
||||
# "name": "Airspy HF+",
|
||||
# "type": "airspyhf",
|
||||
# "ppm": 0,
|
||||
# "rf_gain": "auto",
|
||||
# "profiles": {
|
||||
# "20m": {
|
||||
# "name": "20m",
|
||||
# "center_freq": 14150000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 14070000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "30m": {
|
||||
# "name": "30m",
|
||||
# "center_freq": 10125000,
|
||||
# "samp_rate": 192000,
|
||||
# "start_freq": 10142000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "40m": {
|
||||
# "name": "40m",
|
||||
# "center_freq": 7100000,
|
||||
# "samp_rate": 256000,
|
||||
# "start_freq": 7070000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "80m": {
|
||||
# "name": "80m",
|
||||
# "center_freq": 3650000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 3570000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "49m": {
|
||||
# "name": "49m Broadcast",
|
||||
# "center_freq": 6050000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 6070000,
|
||||
# "start_mod": "am",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# "sdrplay": {
|
||||
# "name": "SDRPlay RSP2",
|
||||
# "type": "sdrplay",
|
||||
# "ppm": 0,
|
||||
# "antenna": "Antenna A",
|
||||
# "profiles": {
|
||||
# "20m": {
|
||||
# "name": "20m",
|
||||
# "center_freq": 14150000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 14070000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "30m": {
|
||||
# "name": "30m",
|
||||
# "center_freq": 10125000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 250000,
|
||||
# "start_freq": 10142000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "40m": {
|
||||
# "name": "40m",
|
||||
# "center_freq": 7100000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 7070000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "80m": {
|
||||
# "name": "80m",
|
||||
# "center_freq": 3650000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 3570000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "49m": {
|
||||
# "name": "49m Broadcast",
|
||||
# "center_freq": 6000000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 6070000,
|
||||
# "start_mod": "am",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
#}
|
||||
#lna_gain=8
|
||||
#rf_amp=1
|
||||
#start_rtl_command="hackrf_transfer -s {samp_rate} -f {center_freq} -g {rf_gain} -l{lna_gain} -a{rf_amp} -r-".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm, rf_amp=rf_amp, lna_gain=lna_gain)
|
||||
#format_conversion="csdr convert_s8_f"
|
||||
"""
|
||||
To use a HackRF, compile the HackRF host tools from its "stdout" branch:
|
||||
git clone https://github.com/mossmann/hackrf/
|
||||
cd hackrf
|
||||
git fetch
|
||||
git checkout origin/stdout
|
||||
cd host
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DINSTALL_UDEV_RULES=ON
|
||||
make
|
||||
sudo make install
|
||||
"""
|
||||
|
||||
# >> Sound card SDR (needs ALSA)
|
||||
# I did not have the chance to properly test it.
|
||||
#samp_rate = 96000
|
||||
#start_rtl_command="arecord -f S16_LE -r {samp_rate} -c2 -".format(samp_rate=samp_rate)
|
||||
#format_conversion="csdr convert_s16_f | csdr gain_ff 30"
|
||||
|
||||
# >> /dev/urandom test signal source
|
||||
# samp_rate = 2400000
|
||||
# start_rtl_command="cat /dev/urandom | (pv -qL `python -c 'print int({samp_rate} * 2.2)'` 2>&1)".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate)
|
||||
# format_conversion="csdr convert_u8_f"
|
||||
|
||||
# >> Pre-recorded raw I/Q file as signal source
|
||||
# You will have to correctly specify: samp_rate, center_freq, format_conversion in order to correctly play an I/Q file.
|
||||
#start_rtl_command="(while true; do cat my_iq_file.raw; done) | csdr flowcontrol {sr} 20 ".format(sr=samp_rate*2*1.05)
|
||||
#format_conversion="csdr convert_u8_f"
|
||||
|
||||
#>> The rx_sdr command works with a variety of SDR harware: RTL-SDR, HackRF, SDRplay, UHD, Airspy, Red Pitaya, audio devices, etc.
|
||||
# It will auto-detect your SDR hardware if the following tools are installed:
|
||||
# * the vendor provided driver and library,
|
||||
# * the vendor-specific SoapySDR wrapper library,
|
||||
# * and SoapySDR itself.
|
||||
# Check out this article on the OpenWebRX Wiki: https://github.com/simonyiszk/openwebrx/wiki/Using-rx_tools-with-OpenWebRX/
|
||||
#start_rtl_command="rx_sdr -F CF32 -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm)
|
||||
#format_conversion=""
|
||||
|
||||
# >> gr-osmosdr signal source using GNU Radio (follow this guide: https://github.com/simonyiszk/openwebrx/wiki/Using-GrOsmoSDR-as-signal-source)
|
||||
#start_rtl_command="cat /tmp/osmocom_fifo"
|
||||
#format_conversion=""
|
||||
|
||||
# ==== Misc settings ====
|
||||
|
||||
shown_center_freq = center_freq #you can change this if you use an upconverter
|
||||
|
||||
client_audio_buffer_size = 5
|
||||
#increasing client_audio_buffer_size will:
|
||||
# - also increase the latency
|
||||
# - decrease the chance of audio underruns
|
||||
|
||||
start_freq = center_freq
|
||||
start_mod = "nfm" #nfm, am, lsb, usb, cw
|
||||
|
||||
iq_server_port = 4951 #TCP port for ncat to listen on. It will send I/Q data over its connections, for internal use in OpenWebRX. It is only accessible from the localhost by default.
|
||||
|
||||
#access_log = "~/openwebrx_access.log"
|
||||
|
||||
# ==== Color themes ====
|
||||
|
||||
### google turbo colormap (see: https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html)
|
||||
#waterfall_scheme = "GoogleTurboWaterfall"
|
||||
|
||||
### original theme by teejez:
|
||||
#waterfall_scheme = "TeejeezWaterfall"
|
||||
#A guide is available to help you set these values: https://github.com/simonyiszk/openwebrx/wiki/Calibrating-waterfall-display-levels
|
||||
|
||||
### default theme by teejez:
|
||||
waterfall_colors = "[0x000000ff,0x0000ffff,0x00ffffff,0x00ff00ff,0xffff00ff,0xff0000ff,0xff00ffff,0xffffffff]"
|
||||
waterfall_min_level = -88 #in dB
|
||||
waterfall_max_level = -20
|
||||
waterfall_auto_level_margin = (5, 40)
|
||||
### old theme by HA7ILM:
|
||||
#waterfall_scheme = "Ha7ilmWaterfall"
|
||||
#waterfall_colors = "[0x000000ff,0x2e6893ff, 0x69a5d0ff, 0x214b69ff, 0x9dc4e0ff, 0xfff775ff, 0xff8a8aff, 0xb20000ff]"
|
||||
#waterfall_min_level = -115 #in dB
|
||||
#waterfall_max_level = 0
|
||||
#waterfall_auto_level_margin = (20, 30)
|
||||
##For the old colors, you might also want to set [fft_voverlap_factor] to 0.
|
||||
|
||||
### custom waterfall schemes can be configured like this:
|
||||
#waterfall_scheme = "CustomWaterfall"
|
||||
#waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000]
|
||||
|
||||
### Waterfall calibration
|
||||
#waterfall_levels = {"min": -88, "max": -20} # in dB
|
||||
|
||||
#waterfall_auto_levels = {"min": 3, "max": 10}
|
||||
#waterfall_auto_min_range = 50
|
||||
|
||||
# Note: When the auto waterfall level button is clicked, the following happens:
|
||||
# [waterfall_levels.min] = [current_min_power_level] - [waterfall_auto_levels["min"]]
|
||||
# [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_levels["max"]]
|
||||
#Note: When the auto waterfall level button is clicked, the following happens:
|
||||
# [waterfall_min_level] = [current_min_power_level] - [waterfall_auto_level_margin[0]]
|
||||
# [waterfall_max_level] = [current_max_power_level] + [waterfall_auto_level_margin[1]]
|
||||
#
|
||||
# ___|__________________________________|____________________________________|__________________________________|___> signal power
|
||||
# \_waterfall_auto_levels["min"]_/ |__ current_min_power_level | \_waterfall_auto_levels["max"]_/
|
||||
# current_max_power_level __|
|
||||
# ___|____________________________________|____________________________________|____________________________________|___> signal power
|
||||
# \_waterfall_auto_level_margin[0]_/ |__ current_min_power_level | \_waterfall_auto_level_margin[1]_/
|
||||
# current_max_power_level __|
|
||||
|
||||
# This setting allows you to modify the precision of the frequency displays in OpenWebRX.
|
||||
# Set this to exponent of 10 to select the most precise digit in Hz you'd like to see
|
||||
# examples:
|
||||
# a value of 2 selects 10^2 = 100Hz tuning precision (default):
|
||||
#tuning_precision = 2
|
||||
# a value of 1 selects 10^1 = 10Hz tuning precision:
|
||||
#tuning_precision = 1
|
||||
# 3D view settings
|
||||
mathbox_waterfall_frequency_resolution = 128 #bins
|
||||
mathbox_waterfall_history_length = 10 #seconds
|
||||
mathbox_waterfall_colors = "[0x000000ff,0x2e6893ff, 0x69a5d0ff, 0x214b69ff, 0x9dc4e0ff, 0xfff775ff, 0xff8a8aff, 0xb20000ff]"
|
||||
|
||||
# This setting tells the auto-squelch the offset to add to the current signal level to use as the new squelch level.
|
||||
# Lowering this setting will give you a more sensitive squelch, but it may also cause unwanted squelch openings when
|
||||
# using the auto squelch.
|
||||
#squelch_auto_margin = 10 # in dB
|
||||
# === Experimental settings ===
|
||||
#Warning! The settings below are very experimental.
|
||||
csdr_dynamic_bufsize = False # This allows you to change the buffering mode of csdr.
|
||||
csdr_print_bufsizes = False # This prints the buffer sizes used for csdr processes.
|
||||
csdr_through = False # Setting this True will print out how much data is going into the DSP chains.
|
||||
|
||||
#google_maps_api_key = ""
|
||||
nmux_memory = 50 #in megabytes. This sets the approximate size of the circular buffer used by nmux.
|
||||
|
||||
# how long should positions be visible on the map?
|
||||
# they will start fading out after half of that
|
||||
# in seconds; default: 2 hours
|
||||
#map_position_retention_time = 2 * 60 * 60
|
||||
|
||||
# decoder queue configuration
|
||||
# due to the nature of some operating modes (ft8, ft8, jt9, jt65, wspr and js8), the data is recorded for a given amount
|
||||
# of time (6 seconds up to 2 minutes) and decoded at the end. this can lead to very high peak loads.
|
||||
# to mitigate this, the recordings will be queued and processed in sequence.
|
||||
# the number of workers will limit the total amount of work (one worker will losely occupy one cpu / thread)
|
||||
#decoding_queue_workers = 2
|
||||
# the maximum queue length will cause decodes to be dumped if the workers cannot keep up
|
||||
# if you are running background services, make sure this number is high enough to accept the task influx during peaks
|
||||
# i.e. this should be higher than the number of decoding services running at the same time
|
||||
#decoding_queue_length = 10
|
||||
|
||||
# wsjt decoding depth will allow more results, but will also consume more cpu
|
||||
#wsjt_decoding_depth = 3
|
||||
# can also be set for each mode separately
|
||||
# jt65 seems to be somewhat prone to erroneous decodes, this setting handles that to some extent
|
||||
#wsjt_decoding_depths = {"jt65": 1}
|
||||
|
||||
# FST4 can be transmitted in different intervals. This setting determines which intervals will be decoded.
|
||||
# available values (in seconds): 15, 30, 60, 120, 300, 900, 1800
|
||||
#fst4_enabled_intervals = [15, 30]
|
||||
|
||||
# FST4W can be transmitted in different intervals. This setting determines which intervals will be decoded.
|
||||
# available values (in seconds): 120, 300, 900, 1800
|
||||
#fst4w_enabled_intervals = [120, 300]
|
||||
|
||||
# Q65 allows many combinations of intervals and submodes. This setting determines which combinations will be decoded.
|
||||
# Please use the mode letter followed by the decode interval in seconds to specify the combinations. For example:
|
||||
#q65_enabled_combinations = ["A30", "E120", "C60"]
|
||||
|
||||
# JS8 comes in different speeds: normal, slow, fast, turbo. This setting controls which ones are enabled.
|
||||
#js8_enabled_profiles = ["normal", "slow"]
|
||||
# JS8 decoding depth; higher value will get more results, but will also consume more cpu
|
||||
#js8_decoding_depth = 3
|
||||
|
||||
# Enable background service for decoding digital data. You can find more information at:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Background-decoding
|
||||
#services_enabled = False
|
||||
#services_decoders = ["ft8", "ft4", "wspr", "packet"]
|
||||
|
||||
# === aprs igate settings ===
|
||||
# If you want to share your APRS decodes with the aprs network, configure these settings accordingly.
|
||||
# Make sure that you have set services_enabled to true and customize services_decoders to your needs.
|
||||
#aprs_callsign = "N0CALL"
|
||||
#aprs_igate_enabled = False
|
||||
#aprs_igate_server = "euro.aprs2.net"
|
||||
#aprs_igate_password = ""
|
||||
# beacon uses the receiver_gps setting, so if you enable this, make sure the location is correct there
|
||||
#aprs_igate_beacon = False
|
||||
|
||||
# Uncomment the following to customize gateway beacon details reported to the aprs network
|
||||
# Plese see Dire Wolf's documentation on PBEACON configuration for complete details:
|
||||
# https://github.com/wb2osz/direwolf/raw/master/doc/User-Guide.pdf
|
||||
|
||||
# Symbol in its two-character form as specified by the APRS spec at http://www.aprs.org/symbols/symbols-new.txt
|
||||
# Default: Receive only IGate (do not send msgs back to RF)
|
||||
# aprs_igate_symbol = "R&"
|
||||
|
||||
# Custom comment about igate
|
||||
# Default: OpenWebRX APRS gateway
|
||||
# aprs_igate_comment = "OpenWebRX APRS gateway"
|
||||
|
||||
# Antenna Height and Gain details
|
||||
# Unspecified by default
|
||||
# Antenna height above average terrain (HAAT) in meters
|
||||
# aprs_igate_height = "5"
|
||||
# Antenna gain in dBi
|
||||
# aprs_igate_gain = "0"
|
||||
# Antenna direction (N, NE, E, SE, S, SW, W, NW). Omnidirectional by default
|
||||
# aprs_igate_dir = "NE"
|
||||
|
||||
# === PSK Reporter settings ===
|
||||
# enable this if you want to upload all ft8, ft4 etc spots to pskreporter.info
|
||||
# this also uses the receiver_gps setting from above, so make sure it contains a correct locator
|
||||
#pskreporter_enabled = False
|
||||
#pskreporter_callsign = "N0CALL"
|
||||
# optional antenna information, uncomment to enable
|
||||
#pskreporter_antenna_information = "Dipole"
|
||||
|
||||
# === WSPRNet reporting settings
|
||||
# enable this if you want to upload WSPR spots to wsprnet.ort
|
||||
# in addition to these settings also make sure that receiver_gps contains your correct location
|
||||
#wsprnet_enabled = False
|
||||
#wsprnet_callsign = "N0CALL"
|
||||
#Look up external IP address automatically from icanhazip.com, and use it as [server_hostname]
|
||||
"""
|
||||
print "[openwebrx-config] Detecting external IP address..."
|
||||
import urllib2
|
||||
server_hostname=urllib2.urlopen("http://icanhazip.com").read()[:-1]
|
||||
print "[openwebrx-config] External IP address detected:", server_hostname
|
||||
"""
|
||||
|
424
csdr.py
Executable file
@ -0,0 +1,424 @@
|
||||
"""
|
||||
OpenWebRX csdr plugin: do the signal processing with csdr
|
||||
|
||||
This file is part of OpenWebRX,
|
||||
an open-source SDR receiver software with a web UI.
|
||||
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
import code
|
||||
import signal
|
||||
import fcntl
|
||||
|
||||
class dsp:
|
||||
|
||||
def __init__(self):
|
||||
self.samp_rate = 250000
|
||||
self.output_rate = 11025 #this is default, and cannot be set at the moment
|
||||
self.fft_size = 1024
|
||||
self.fft_fps = 5
|
||||
self.offset_freq = 0
|
||||
self.low_cut = -4000
|
||||
self.high_cut = 4000
|
||||
self.bpf_transition_bw = 320 #Hz, and this is a constant
|
||||
self.ddc_transition_bw_rate = 0.15 # of the IF sample rate
|
||||
self.running = False
|
||||
self.secondary_processes_running = False
|
||||
self.audio_compression = "none"
|
||||
self.fft_compression = "none"
|
||||
self.demodulator = "nfm"
|
||||
self.name = "csdr"
|
||||
self.format_conversion = "csdr convert_u8_f"
|
||||
self.base_bufsize = 512
|
||||
self.nc_port = 4951
|
||||
self.csdr_dynamic_bufsize = False
|
||||
self.csdr_print_bufsizes = False
|
||||
self.csdr_through = False
|
||||
self.squelch_level = 0
|
||||
self.fft_averages = 50
|
||||
self.iqtee = False
|
||||
self.iqtee2 = False
|
||||
self.secondary_demodulator = None
|
||||
self.secondary_fft_size = 1024
|
||||
self.secondary_process_fft = None
|
||||
self.secondary_process_demod = None
|
||||
self.pipe_names=["bpf_pipe", "shift_pipe", "squelch_pipe", "smeter_pipe", "iqtee_pipe", "iqtee2_pipe"]
|
||||
self.secondary_pipe_names=["secondary_shift_pipe"]
|
||||
self.secondary_offset_freq = 1000
|
||||
|
||||
def chain(self,which):
|
||||
any_chain_base="nc -v 127.0.0.1 {nc_port} | "
|
||||
if self.csdr_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | "
|
||||
if self.csdr_through: any_chain_base+="csdr through | "
|
||||
any_chain_base+=self.format_conversion+(" | " if self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | "
|
||||
if which == "fft":
|
||||
fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | " + \
|
||||
("csdr logpower_cf -70 | " if self.fft_averages == 0 else "csdr logaveragepower_cf -70 {fft_size} {fft_averages} | ") + \
|
||||
"csdr fft_exchange_sides_ff {fft_size}"
|
||||
if self.fft_compression=="adpcm":
|
||||
return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}"
|
||||
else:
|
||||
return fft_chain_base
|
||||
chain_begin=any_chain_base+"csdr shift_addition_cc --fifo {shift_pipe} | csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING | csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING | csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 1 | "
|
||||
if self.secondary_demodulator:
|
||||
chain_begin+="csdr tee {iqtee_pipe} | "
|
||||
chain_begin+="csdr tee {iqtee2_pipe} | "
|
||||
chain_end = ""
|
||||
if self.audio_compression=="adpcm":
|
||||
chain_end = " | csdr encode_ima_adpcm_i16_u8"
|
||||
if which == "nfm": return chain_begin + "csdr fmdemod_quadri_cf | csdr limit_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr deemphasis_nfm_ff 11025 | csdr fastagc_ff 1024 | csdr convert_f_s16"+chain_end
|
||||
elif which == "am": return chain_begin + "csdr amdemod_cf | csdr fastdcblock_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end
|
||||
elif which == "ssb": return chain_begin + "csdr realpart_cf | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end
|
||||
|
||||
def secondary_chain(self, which):
|
||||
secondary_chain_base="cat {input_pipe} | "
|
||||
if which == "fft":
|
||||
return secondary_chain_base+"csdr realpart_cf | csdr fft_fc {secondary_fft_input_size} {secondary_fft_block_size} | csdr logpower_cf -70 " + (" | csdr compress_fft_adpcm_f_u8 {secondary_fft_size}" if self.fft_compression=="adpcm" else "")
|
||||
elif which == "bpsk31":
|
||||
return secondary_chain_base + "csdr shift_addition_cc --fifo {secondary_shift_pipe} | " + \
|
||||
"csdr bandpass_fir_fft_cc $(csdr '=-(31.25)/{if_samp_rate}') $(csdr '=(31.25)/{if_samp_rate}') $(csdr '=31.25/{if_samp_rate}') | " + \
|
||||
"csdr simple_agc_cc 0.001 0.5 | " + \
|
||||
"csdr timing_recovery_cc GARDNER {secondary_samples_per_bits} 0.5 2 --add_q | " + \
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr dbpsk_decoder_c_u8 | " + \
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr psk31_varicode_decoder_u8_u8"
|
||||
|
||||
def set_secondary_demodulator(self, what):
|
||||
self.secondary_demodulator = what
|
||||
|
||||
def secondary_fft_block_size(self):
|
||||
return (self.samp_rate/self.decimation)/(self.fft_fps*2) #*2 is there because we do FFT on real signal here
|
||||
|
||||
def secondary_decimation(self):
|
||||
return 1 #currently unused
|
||||
|
||||
def secondary_bpf_cutoff(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return (31.25/2) / self.if_samp_rate()
|
||||
return 0
|
||||
|
||||
def secondary_bpf_transition_bw(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return (31.25/2) / self.if_samp_rate()
|
||||
return 0
|
||||
|
||||
def secondary_samples_per_bits(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return int(round(self.if_samp_rate()/31.25))&~3
|
||||
return 0
|
||||
|
||||
def secondary_bw(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return 31.25
|
||||
|
||||
def start_secondary_demodulator(self):
|
||||
if(not self.secondary_demodulator): return
|
||||
print "[openwebrx] starting secondary demodulator from IF input sampled at %d"%self.if_samp_rate()
|
||||
secondary_command_fft=self.secondary_chain("fft")
|
||||
secondary_command_demod=self.secondary_chain(self.secondary_demodulator)
|
||||
self.try_create_pipes(self.secondary_pipe_names, secondary_command_demod + secondary_command_fft)
|
||||
|
||||
secondary_command_fft=secondary_command_fft.format( \
|
||||
input_pipe=self.iqtee_pipe, \
|
||||
secondary_fft_input_size=self.secondary_fft_size, \
|
||||
secondary_fft_size=self.secondary_fft_size, \
|
||||
secondary_fft_block_size=self.secondary_fft_block_size(), \
|
||||
)
|
||||
secondary_command_demod=secondary_command_demod.format( \
|
||||
input_pipe=self.iqtee2_pipe, \
|
||||
secondary_shift_pipe=self.secondary_shift_pipe, \
|
||||
secondary_decimation=self.secondary_decimation(), \
|
||||
secondary_samples_per_bits=self.secondary_samples_per_bits(), \
|
||||
secondary_bpf_cutoff=self.secondary_bpf_cutoff(), \
|
||||
secondary_bpf_transition_bw=self.secondary_bpf_transition_bw(), \
|
||||
if_samp_rate=self.if_samp_rate()
|
||||
)
|
||||
|
||||
print "[openwebrx-dsp-plugin:csdr] secondary command (fft) =", secondary_command_fft
|
||||
print "[openwebrx-dsp-plugin:csdr] secondary command (demod) =", secondary_command_demod
|
||||
#code.interact(local=locals())
|
||||
my_env=os.environ.copy()
|
||||
#if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1";
|
||||
if self.csdr_print_bufsizes: my_env["CSDR_PRINT_BUFSIZES"]="1";
|
||||
self.secondary_process_fft = subprocess.Popen(secondary_command_fft, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env)
|
||||
print "[openwebrx-dsp-plugin:csdr] Popen on secondary command (fft)"
|
||||
self.secondary_process_demod = subprocess.Popen(secondary_command_demod, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env) #TODO digimodes
|
||||
print "[openwebrx-dsp-plugin:csdr] Popen on secondary command (demod)" #TODO digimodes
|
||||
self.secondary_processes_running = True
|
||||
|
||||
#open control pipes for csdr and send initialization data
|
||||
# print "==========> 1"
|
||||
if self.secondary_shift_pipe != None: #TODO digimodes
|
||||
# print "==========> 2", self.secondary_shift_pipe
|
||||
self.secondary_shift_pipe_file=open(self.secondary_shift_pipe,"w") #TODO digimodes
|
||||
# print "==========> 3"
|
||||
self.set_secondary_offset_freq(self.secondary_offset_freq) #TODO digimodes
|
||||
# print "==========> 4"
|
||||
|
||||
self.set_pipe_nonblocking(self.secondary_process_demod.stdout)
|
||||
self.set_pipe_nonblocking(self.secondary_process_fft.stdout)
|
||||
|
||||
def set_secondary_offset_freq(self, value):
|
||||
self.secondary_offset_freq=value
|
||||
if self.secondary_processes_running:
|
||||
self.secondary_shift_pipe_file.write("%g\n"%(-float(self.secondary_offset_freq)/self.if_samp_rate()))
|
||||
self.secondary_shift_pipe_file.flush()
|
||||
|
||||
def stop_secondary_demodulator(self):
|
||||
if self.secondary_processes_running == False: return
|
||||
self.try_delete_pipes(self.secondary_pipe_names)
|
||||
if self.secondary_process_fft: os.killpg(os.getpgid(self.secondary_process_fft.pid), signal.SIGTERM)
|
||||
if self.secondary_process_demod: os.killpg(os.getpgid(self.secondary_process_demod.pid), signal.SIGTERM)
|
||||
self.secondary_processes_running = False
|
||||
|
||||
def read_secondary_demod(self, size):
|
||||
return self.secondary_process_demod.stdout.read(size)
|
||||
|
||||
def read_secondary_fft(self, size):
|
||||
return self.secondary_process_fft.stdout.read(size)
|
||||
|
||||
def get_secondary_demodulator(self):
|
||||
return self.secondary_demodulator
|
||||
|
||||
def set_secondary_fft_size(self,secondary_fft_size):
|
||||
#to change this, restart is required
|
||||
self.secondary_fft_size=secondary_fft_size
|
||||
|
||||
def set_audio_compression(self,what):
|
||||
self.audio_compression = what
|
||||
|
||||
def set_fft_compression(self,what):
|
||||
self.fft_compression = what
|
||||
|
||||
def get_fft_bytes_to_read(self):
|
||||
if self.fft_compression=="none": return self.fft_size*4
|
||||
if self.fft_compression=="adpcm": return (self.fft_size/2)+(10/2)
|
||||
|
||||
def get_secondary_fft_bytes_to_read(self):
|
||||
if self.fft_compression=="none": return self.secondary_fft_size*4
|
||||
if self.fft_compression=="adpcm": return (self.secondary_fft_size/2)+(10/2)
|
||||
|
||||
def set_samp_rate(self,samp_rate):
|
||||
#to change this, restart is required
|
||||
self.samp_rate=samp_rate
|
||||
self.decimation=1
|
||||
while self.samp_rate/(self.decimation+1)>self.output_rate:
|
||||
self.decimation+=1
|
||||
self.last_decimation=float(self.if_samp_rate())/self.output_rate
|
||||
|
||||
def if_samp_rate(self):
|
||||
return self.samp_rate/self.decimation
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_output_rate(self):
|
||||
return self.output_rate
|
||||
|
||||
def set_output_rate(self,output_rate):
|
||||
self.output_rate=output_rate
|
||||
self.set_samp_rate(self.samp_rate) #as it depends on output_rate
|
||||
|
||||
def set_demodulator(self,demodulator):
|
||||
#to change this, restart is required
|
||||
self.demodulator=demodulator
|
||||
|
||||
def get_demodulator(self):
|
||||
return self.demodulator
|
||||
|
||||
def set_fft_size(self,fft_size):
|
||||
#to change this, restart is required
|
||||
self.fft_size=fft_size
|
||||
|
||||
def set_fft_fps(self,fft_fps):
|
||||
#to change this, restart is required
|
||||
self.fft_fps=fft_fps
|
||||
|
||||
def set_fft_averages(self,fft_averages):
|
||||
#to change this, restart is required
|
||||
self.fft_averages=fft_averages
|
||||
|
||||
def fft_block_size(self):
|
||||
if self.fft_averages == 0: return self.samp_rate/self.fft_fps
|
||||
else: return self.samp_rate/self.fft_fps/self.fft_averages
|
||||
|
||||
def set_format_conversion(self,format_conversion):
|
||||
self.format_conversion=format_conversion
|
||||
|
||||
def set_offset_freq(self,offset_freq):
|
||||
self.offset_freq=offset_freq
|
||||
if self.running:
|
||||
self.shift_pipe_file.write("%g\n"%(-float(self.offset_freq)/self.samp_rate))
|
||||
self.shift_pipe_file.flush()
|
||||
|
||||
def set_bpf(self,low_cut,high_cut):
|
||||
self.low_cut=low_cut
|
||||
self.high_cut=high_cut
|
||||
if self.running:
|
||||
self.bpf_pipe_file.write( "%g %g\n"%(float(self.low_cut)/self.if_samp_rate(), float(self.high_cut)/self.if_samp_rate()) )
|
||||
self.bpf_pipe_file.flush()
|
||||
|
||||
def get_bpf(self):
|
||||
return [self.low_cut, self.high_cut]
|
||||
|
||||
def set_squelch_level(self, squelch_level):
|
||||
self.squelch_level=squelch_level
|
||||
if self.running:
|
||||
self.squelch_pipe_file.write( "%g\n"%(float(self.squelch_level)) )
|
||||
self.squelch_pipe_file.flush()
|
||||
|
||||
def get_smeter_level(self):
|
||||
if self.running:
|
||||
line=self.smeter_pipe_file.readline()
|
||||
return float(line[:-1])
|
||||
|
||||
def mkfifo(self,path):
|
||||
try:
|
||||
os.unlink(path)
|
||||
except:
|
||||
pass
|
||||
os.mkfifo(path)
|
||||
|
||||
def ddc_transition_bw(self):
|
||||
return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate))
|
||||
|
||||
def try_create_pipes(self, pipe_names, command_base):
|
||||
# print "try_create_pipes"
|
||||
for pipe_name in pipe_names:
|
||||
# print "\t"+pipe_name
|
||||
if "{"+pipe_name+"}" in command_base:
|
||||
setattr(self, pipe_name, self.pipe_base_path+pipe_name)
|
||||
self.mkfifo(getattr(self, pipe_name))
|
||||
else:
|
||||
setattr(self, pipe_name, None)
|
||||
|
||||
def try_delete_pipes(self, pipe_names):
|
||||
for pipe_name in pipe_names:
|
||||
pipe_path = getattr(self,pipe_name,None)
|
||||
if pipe_path:
|
||||
try: os.unlink(pipe_path)
|
||||
except Exception as e: print "[openwebrx-dsp-plugin:csdr] try_delete_pipes() ::", e
|
||||
|
||||
def set_pipe_nonblocking(self, pipe):
|
||||
flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
|
||||
fcntl.fcntl(pipe, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
def start(self):
|
||||
command_base=self.chain(self.demodulator)
|
||||
|
||||
#create control pipes for csdr
|
||||
self.pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self))
|
||||
# self.bpf_pipe = self.shift_pipe = self.squelch_pipe = self.smeter_pipe = None
|
||||
|
||||
self.try_create_pipes(self.pipe_names, command_base)
|
||||
|
||||
# if "{bpf_pipe}" in command_base:
|
||||
# self.bpf_pipe=pipe_base_path+"bpf"
|
||||
# self.mkfifo(self.bpf_pipe)
|
||||
# if "{shift_pipe}" in command_base:
|
||||
# self.shift_pipe=pipe_base_path+"shift"
|
||||
# self.mkfifo(self.shift_pipe)
|
||||
# if "{squelch_pipe}" in command_base:
|
||||
# self.squelch_pipe=pipe_base_path+"squelch"
|
||||
# self.mkfifo(self.squelch_pipe)
|
||||
# if "{smeter_pipe}" in command_base:
|
||||
# self.smeter_pipe=pipe_base_path+"smeter"
|
||||
# self.mkfifo(self.smeter_pipe)
|
||||
# if "{iqtee_pipe}" in command_base:
|
||||
# self.iqtee_pipe=pipe_base_path+"iqtee"
|
||||
# self.mkfifo(self.iqtee_pipe)
|
||||
# if "{iqtee2_pipe}" in command_base:
|
||||
# self.iqtee2_pipe=pipe_base_path+"iqtee2"
|
||||
# self.mkfifo(self.iqtee2_pipe)
|
||||
|
||||
#run the command
|
||||
command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \
|
||||
last_decimation=self.last_decimation, fft_size=self.fft_size, fft_block_size=self.fft_block_size(), fft_averages=self.fft_averages, \
|
||||
bpf_transition_bw=float(self.bpf_transition_bw)/self.if_samp_rate(), ddc_transition_bw=self.ddc_transition_bw(), \
|
||||
flowcontrol=int(self.samp_rate*2), start_bufsize=self.base_bufsize*self.decimation, nc_port=self.nc_port, \
|
||||
squelch_pipe=self.squelch_pipe, smeter_pipe=self.smeter_pipe, iqtee_pipe=self.iqtee_pipe, iqtee2_pipe=self.iqtee2_pipe )
|
||||
|
||||
print "[openwebrx-dsp-plugin:csdr] Command =",command
|
||||
#code.interact(local=locals())
|
||||
my_env=os.environ.copy()
|
||||
if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1";
|
||||
if self.csdr_print_bufsizes: my_env["CSDR_PRINT_BUFSIZES"]="1";
|
||||
self.process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env)
|
||||
self.running = True
|
||||
|
||||
#open control pipes for csdr and send initialization data
|
||||
if self.bpf_pipe != None:
|
||||
self.bpf_pipe_file=open(self.bpf_pipe,"w")
|
||||
self.set_bpf(self.low_cut,self.high_cut)
|
||||
if self.shift_pipe != None:
|
||||
self.shift_pipe_file=open(self.shift_pipe,"w")
|
||||
self.set_offset_freq(self.offset_freq)
|
||||
if self.squelch_pipe != None:
|
||||
self.squelch_pipe_file=open(self.squelch_pipe,"w")
|
||||
self.set_squelch_level(self.squelch_level)
|
||||
if self.smeter_pipe != None:
|
||||
self.smeter_pipe_file=open(self.smeter_pipe,"r")
|
||||
self.set_pipe_nonblocking(self.smeter_pipe_file)
|
||||
|
||||
self.start_secondary_demodulator()
|
||||
|
||||
def read(self,size):
|
||||
return self.process.stdout.read(size)
|
||||
|
||||
def stop(self):
|
||||
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
|
||||
self.stop_secondary_demodulator()
|
||||
#if(self.process.poll()!=None):return # returns None while subprocess is running
|
||||
#while(self.process.poll()==None):
|
||||
# #self.process.kill()
|
||||
# print "killproc",os.getpgid(self.process.pid),self.process.pid
|
||||
# os.killpg(self.process.pid, signal.SIGTERM)
|
||||
#
|
||||
# time.sleep(0.1)
|
||||
|
||||
self.try_delete_pipes(self.pipe_names)
|
||||
|
||||
# if self.bpf_pipe:
|
||||
# try: os.unlink(self.bpf_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe
|
||||
# if self.shift_pipe:
|
||||
# try: os.unlink(self.shift_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.shift_pipe
|
||||
# if self.squelch_pipe:
|
||||
# try: os.unlink(self.squelch_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.squelch_pipe
|
||||
# if self.smeter_pipe:
|
||||
# try: os.unlink(self.smeter_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.smeter_pipe
|
||||
# if self.iqtee_pipe:
|
||||
# try: os.unlink(self.iqtee_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.iqtee_pipe
|
||||
# if self.iqtee2_pipe:
|
||||
# try: os.unlink(self.iqtee2_pipe)
|
||||
# except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.iqtee2_pipe
|
||||
|
||||
self.running = False
|
||||
|
||||
def restart(self):
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def __del__(self):
|
||||
self.stop()
|
||||
del(self.process)
|
836
csdr/__init__.py
@ -1,836 +0,0 @@
|
||||
"""
|
||||
OpenWebRX csdr plugin: do the signal processing with csdr
|
||||
|
||||
This file is part of OpenWebRX,
|
||||
an open-source SDR receiver software with a web UI.
|
||||
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
|
||||
Copyright (c) 2019-2021 by Jakob Ketterl <dd5jfk@darc.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import signal
|
||||
import threading
|
||||
import math
|
||||
from functools import partial
|
||||
|
||||
from csdr.output import Output
|
||||
|
||||
from owrx.kiss import KissClient, DirewolfConfig, DirewolfConfigSubscriber
|
||||
from owrx.audio.chopper import AudioChopper
|
||||
|
||||
from csdr.pipe import Pipe
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Dsp(DirewolfConfigSubscriber):
|
||||
def __init__(self, output: Output):
|
||||
self.samp_rate = 250000
|
||||
self.output_rate = 11025
|
||||
self.hd_output_rate = 44100
|
||||
self.fft_size = 1024
|
||||
self.fft_fps = 5
|
||||
self.center_freq = 0
|
||||
self.offset_freq = 0
|
||||
self.low_cut = -4000
|
||||
self.high_cut = 4000
|
||||
self.bpf_transition_bw = 320 # Hz, and this is a constant
|
||||
self.ddc_transition_bw_rate = 0.15 # of the IF sample rate
|
||||
self.running = False
|
||||
self.secondary_processes_running = False
|
||||
self.audio_compression = "none"
|
||||
self.fft_compression = "none"
|
||||
self.demodulator = "nfm"
|
||||
self.name = "csdr"
|
||||
self.base_bufsize = 512
|
||||
self.decimation = None
|
||||
self.last_decimation = None
|
||||
self.nc_port = None
|
||||
self.squelch_level = -150
|
||||
self.fft_averages = 50
|
||||
self.wfm_deemphasis_tau = 50e-6
|
||||
self.iqtee = False
|
||||
self.iqtee2 = False
|
||||
self.secondary_demodulator = None
|
||||
self.secondary_fft_size = 1024
|
||||
self.secondary_process_fft = None
|
||||
self.secondary_process_demod = None
|
||||
self.pipe_names = {
|
||||
"bpf_pipe": Pipe.WRITE,
|
||||
"shift_pipe": Pipe.WRITE,
|
||||
"squelch_pipe": Pipe.WRITE,
|
||||
"smeter_pipe": Pipe.READ,
|
||||
"meta_pipe": Pipe.READ,
|
||||
"iqtee_pipe": Pipe.NONE,
|
||||
"iqtee2_pipe": Pipe.NONE,
|
||||
"dmr_control_pipe": Pipe.WRITE,
|
||||
}
|
||||
self.pipes = {}
|
||||
self.secondary_pipe_names = {"secondary_shift_pipe": Pipe.WRITE}
|
||||
self.secondary_offset_freq = 1000
|
||||
self.unvoiced_quality = 1
|
||||
self.modification_lock = threading.Lock()
|
||||
self.output = output
|
||||
|
||||
self.temporary_directory = None
|
||||
self.pipe_base_path = None
|
||||
self.set_temporary_directory("/tmp")
|
||||
|
||||
self.is_service = False
|
||||
self.direwolf_config = None
|
||||
self.direwolf_config_path = None
|
||||
self.process = None
|
||||
|
||||
def set_service(self, flag=True):
|
||||
self.is_service = flag
|
||||
|
||||
def set_temporary_directory(self, what):
|
||||
self.temporary_directory = what
|
||||
self.pipe_base_path = "{tmp_dir}/openwebrx_pipe_".format(tmp_dir=self.temporary_directory)
|
||||
|
||||
def chain(self, which):
|
||||
chain = ["nc -v 127.0.0.1 {nc_port}"]
|
||||
if which == "fft":
|
||||
chain += [
|
||||
"csdr fft_cc {fft_size} {fft_block_size}",
|
||||
"csdr logpower_cf -70"
|
||||
if self.fft_averages == 0
|
||||
else "csdr logaveragepower_cf -70 {fft_size} {fft_averages}",
|
||||
"csdr fft_exchange_sides_ff {fft_size}",
|
||||
]
|
||||
if self.fft_compression == "adpcm":
|
||||
chain += ["csdr compress_fft_adpcm_f_u8 {fft_size}"]
|
||||
return chain
|
||||
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
|
||||
if self.decimation > 1:
|
||||
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
||||
chain += ["csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING"]
|
||||
if self.output.supports_type("smeter"):
|
||||
chain += [
|
||||
"csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 {smeter_report_every}"
|
||||
]
|
||||
if self.secondary_demodulator:
|
||||
if self.output.supports_type("secondary_fft"):
|
||||
chain += ["csdr tee {iqtee_pipe}"]
|
||||
chain += ["csdr tee {iqtee2_pipe}"]
|
||||
# early exit if we don't want audio
|
||||
if not self.output.supports_type("audio"):
|
||||
return chain
|
||||
# safe some cpu cycles... no need to decimate if decimation factor is 1
|
||||
last_decimation_block = []
|
||||
if self.last_decimation >= 2.0:
|
||||
# activate prefilter if signal has been oversampled, e.g. WFM
|
||||
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation} 12 --prefilter"]
|
||||
elif self.last_decimation != 1.0:
|
||||
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
if which == "nfm":
|
||||
chain += ["csdr fmdemod_quadri_cf", "csdr limit_ff"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr deemphasis_nfm_ff {audio_rate}",
|
||||
"csdr agc_ff --profile slow --max 3",
|
||||
]
|
||||
if self.get_audio_rate() != self.get_output_rate():
|
||||
chain += [
|
||||
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
||||
]
|
||||
else:
|
||||
chain += ["csdr convert_f_s16"]
|
||||
elif which == "wfm":
|
||||
chain += [
|
||||
"csdr fmdemod_quadri_cf",
|
||||
"csdr limit_ff",
|
||||
]
|
||||
chain += last_decimation_block
|
||||
chain += ["csdr deemphasis_wfm_ff {audio_rate} {wfm_deemphasis_tau}", "csdr convert_f_s16"]
|
||||
elif self.isDigitalVoice(which):
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += last_decimation_block
|
||||
# dsd modes
|
||||
if which in ["dstar", "nxdn"]:
|
||||
chain += ["dc_block", "csdr limit_ff", "csdr convert_f_s16"]
|
||||
if which == "dstar":
|
||||
chain += ["dsd -fd -i - -o - -u {unvoiced_quality} -g -1 "]
|
||||
elif which == "nxdn":
|
||||
chain += ["dsd -fi -i - -o - -u {unvoiced_quality} -g -1 "]
|
||||
chain += [
|
||||
"digitalvoice_filter",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
# m17
|
||||
elif which == "m17":
|
||||
chain += [
|
||||
"dc_block",
|
||||
"csdr limit_ff",
|
||||
"csdr convert_f_s16",
|
||||
"m17-demod",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
# digiham modes
|
||||
else:
|
||||
chain += ["dc_block", "rrc_filter", "gfsk_demodulator"]
|
||||
if which == "dmr":
|
||||
chain += [
|
||||
"dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
|
||||
"mbe_synthesizer -f -u {unvoiced_quality}",
|
||||
]
|
||||
elif which == "ysf":
|
||||
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y -f -u {unvoiced_quality}"]
|
||||
max_gain = 0.005
|
||||
chain += [
|
||||
"digitalvoice_filter -f",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_ff --max 0.005 --initial 0.0005",
|
||||
"sox -t raw -r 8000 -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "am":
|
||||
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr agc_ff --profile slow --initial 200",
|
||||
"csdr convert_f_s16",
|
||||
]
|
||||
elif self.isFreeDV(which):
|
||||
chain += ["csdr realpart_cf"]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr agc_ff",
|
||||
"csdr convert_f_s16",
|
||||
"freedv_rx 1600 - -",
|
||||
"csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif self.isDrm(which):
|
||||
if self.last_decimation != 1.0:
|
||||
# we are still dealing with complex samples here, so the regular last_decimation_block doesn't fit
|
||||
chain += ["csdr fractional_decimator_cc {last_decimation}"]
|
||||
chain += [
|
||||
"csdr convert_f_s16",
|
||||
"dream -c 6 --sigsrate 48000 --audsrate 48000 -I - -O -",
|
||||
"sox -t raw -r 48000 -e signed-integer -b 16 -c 2 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "ssb":
|
||||
chain += ["csdr realpart_cf"]
|
||||
chain += last_decimation_block
|
||||
chain += ["csdr agc_ff"]
|
||||
# fixed sample rate necessary for the wsjt-x tools. fix with sox...
|
||||
if self.get_audio_rate() != self.get_output_rate():
|
||||
chain += [
|
||||
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
||||
]
|
||||
else:
|
||||
chain += ["csdr convert_f_s16"]
|
||||
|
||||
if self.audio_compression == "adpcm":
|
||||
chain += ["csdr encode_ima_adpcm_i16_u8"]
|
||||
return chain
|
||||
|
||||
def secondary_chain(self, which):
|
||||
chain = ["cat {input_pipe}"]
|
||||
if which == "fft":
|
||||
chain += [
|
||||
"csdr fft_cc {secondary_fft_input_size} {secondary_fft_block_size}",
|
||||
"csdr logpower_cf -70"
|
||||
if self.fft_averages == 0
|
||||
else "csdr logaveragepower_cf -70 {secondary_fft_size} {fft_averages}",
|
||||
"csdr fft_exchange_sides_ff {secondary_fft_input_size}",
|
||||
]
|
||||
if self.fft_compression == "adpcm":
|
||||
chain += ["csdr compress_fft_adpcm_f_u8 {secondary_fft_size}"]
|
||||
return chain
|
||||
elif which == "bpsk31" or which == "bpsk63":
|
||||
return chain + [
|
||||
"csdr shift_addfast_cc --fifo {secondary_shift_pipe}",
|
||||
"csdr bandpass_fir_fft_cc -{secondary_bpf_cutoff} {secondary_bpf_cutoff} {secondary_bpf_cutoff}",
|
||||
"csdr simple_agc_cc 0.001 0.5",
|
||||
"csdr timing_recovery_cc GARDNER {secondary_samples_per_bits} 0.5 2 --add_q",
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr dbpsk_decoder_c_u8",
|
||||
"CSDR_FIXED_BUFSIZE=1 csdr psk31_varicode_decoder_u8_u8",
|
||||
]
|
||||
elif self.isWsjtMode(which) or self.isJs8(which):
|
||||
chain += ["csdr realpart_cf"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
return chain + ["csdr agc_ff", "csdr convert_f_s16"]
|
||||
elif which == "packet":
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
return chain + ["csdr convert_f_s16", "direwolf -c {direwolf_config} -r {audio_rate} -t 0 -q d -q h 1>&2"]
|
||||
elif which == "pocsag":
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
if self.last_decimation != 1.0:
|
||||
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
||||
return chain + ["fsk_demodulator -i", "pocsag_decoder"]
|
||||
|
||||
def set_secondary_demodulator(self, what):
|
||||
if self.get_secondary_demodulator() == what:
|
||||
return
|
||||
self.secondary_demodulator = what
|
||||
self.calculate_decimation()
|
||||
self.restart()
|
||||
|
||||
def secondary_fft_block_size(self):
|
||||
base = (self.samp_rate / self.decimation) / (self.fft_fps * 2)
|
||||
if self.fft_averages == 0:
|
||||
return base
|
||||
return base / self.fft_averages
|
||||
|
||||
def secondary_decimation(self):
|
||||
return 1 # currently unused
|
||||
|
||||
def secondary_bpf_cutoff(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return 31.25 / self.if_samp_rate()
|
||||
elif self.secondary_demodulator == "bpsk63":
|
||||
return 62.5 / self.if_samp_rate()
|
||||
return 0
|
||||
|
||||
def secondary_bpf_transition_bw(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return 31.25 / self.if_samp_rate()
|
||||
elif self.secondary_demodulator == "bpsk63":
|
||||
return 62.5 / self.if_samp_rate()
|
||||
return 0
|
||||
|
||||
def secondary_samples_per_bits(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return int(round(self.if_samp_rate() / 31.25)) & ~3
|
||||
elif self.secondary_demodulator == "bpsk63":
|
||||
return int(round(self.if_samp_rate() / 62.5)) & ~3
|
||||
return 0
|
||||
|
||||
def secondary_bw(self):
|
||||
if self.secondary_demodulator == "bpsk31":
|
||||
return 31.25
|
||||
elif self.secondary_demodulator == "bpsk63":
|
||||
return 62.5
|
||||
|
||||
def start_secondary_demodulator(self):
|
||||
if not self.secondary_demodulator:
|
||||
return
|
||||
logger.debug("starting secondary demodulator from IF input sampled at %d" % self.if_samp_rate())
|
||||
secondary_command_demod = " | ".join(self.secondary_chain(self.secondary_demodulator))
|
||||
self.try_create_pipes(self.secondary_pipe_names, secondary_command_demod)
|
||||
self.try_create_configs(secondary_command_demod)
|
||||
|
||||
secondary_command_demod = secondary_command_demod.format(
|
||||
input_pipe=self.pipes["iqtee2_pipe"],
|
||||
secondary_shift_pipe=self.pipes["secondary_shift_pipe"],
|
||||
secondary_decimation=self.secondary_decimation(),
|
||||
secondary_samples_per_bits=self.secondary_samples_per_bits(),
|
||||
secondary_bpf_cutoff=self.secondary_bpf_cutoff(),
|
||||
secondary_bpf_transition_bw=self.secondary_bpf_transition_bw(),
|
||||
if_samp_rate=self.if_samp_rate(),
|
||||
last_decimation=self.last_decimation,
|
||||
audio_rate=self.get_audio_rate(),
|
||||
direwolf_config=self.direwolf_config_path,
|
||||
)
|
||||
|
||||
logger.debug("secondary command (demod) = %s", secondary_command_demod)
|
||||
if self.output.supports_type("secondary_fft"):
|
||||
secondary_command_fft = " | ".join(self.secondary_chain("fft"))
|
||||
secondary_command_fft = secondary_command_fft.format(
|
||||
input_pipe=self.pipes["iqtee_pipe"],
|
||||
secondary_fft_input_size=self.secondary_fft_size,
|
||||
secondary_fft_size=self.secondary_fft_size,
|
||||
secondary_fft_block_size=self.secondary_fft_block_size(),
|
||||
fft_averages=self.fft_averages,
|
||||
)
|
||||
logger.debug("secondary command (fft) = %s", secondary_command_fft)
|
||||
|
||||
self.secondary_process_fft = subprocess.Popen(
|
||||
secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True
|
||||
)
|
||||
self.output.send_output(
|
||||
"secondary_fft",
|
||||
partial(self.secondary_process_fft.stdout.read, int(self.get_secondary_fft_bytes_to_read())),
|
||||
)
|
||||
|
||||
# direwolf does not provide any meaningful data on stdout
|
||||
# more specifically, it doesn't provide any data. if however, for any strange reason, it would start to do so,
|
||||
# it would block if not read. by piping it to devnull, we avoid a potential pitfall here.
|
||||
secondary_output = subprocess.DEVNULL if self.isPacket() else subprocess.PIPE
|
||||
self.secondary_process_demod = subprocess.Popen(
|
||||
secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True
|
||||
)
|
||||
self.secondary_processes_running = True
|
||||
|
||||
if self.isWsjtMode() or self.isJs8():
|
||||
chopper = AudioChopper(self, self.get_secondary_demodulator())
|
||||
chopper.send_output("audio", self.secondary_process_demod.stdout.read)
|
||||
output_type = "js8_demod" if self.isJs8() else "wsjt_demod"
|
||||
self.output.send_output(output_type, chopper.read)
|
||||
elif self.isPacket():
|
||||
# we best get the ax25 packets from the kiss socket
|
||||
kiss = KissClient(self.direwolf_config.getPort())
|
||||
self.output.send_output("packet_demod", kiss.read)
|
||||
elif self.isPocsag():
|
||||
self.output.send_output("pocsag_demod", self.secondary_process_demod.stdout.readline)
|
||||
else:
|
||||
self.output.send_output("secondary_demod", partial(self.secondary_process_demod.stdout.read, 1))
|
||||
|
||||
# open control pipes for csdr and send initialization data
|
||||
if self.has_pipe("secondary_shift_pipe"): # TODO digimodes
|
||||
self.set_secondary_offset_freq(self.secondary_offset_freq) # TODO digimodes
|
||||
|
||||
def set_secondary_offset_freq(self, value):
|
||||
self.secondary_offset_freq = value
|
||||
if self.secondary_processes_running and self.has_pipe("secondary_shift_pipe"):
|
||||
self.pipes["secondary_shift_pipe"].write(
|
||||
"%g\n" % (-float(self.secondary_offset_freq) / self.if_samp_rate())
|
||||
)
|
||||
|
||||
def stop_secondary_demodulator(self):
|
||||
if not self.secondary_processes_running:
|
||||
return
|
||||
self.try_delete_pipes(self.secondary_pipe_names)
|
||||
self.try_delete_configs()
|
||||
if self.secondary_process_fft:
|
||||
try:
|
||||
os.killpg(os.getpgid(self.secondary_process_fft.pid), signal.SIGTERM)
|
||||
# drain any leftover data to free file descriptors
|
||||
self.secondary_process_fft.communicate()
|
||||
self.secondary_process_fft = None
|
||||
except ProcessLookupError:
|
||||
# been killed by something else, ignore
|
||||
pass
|
||||
if self.secondary_process_demod:
|
||||
try:
|
||||
os.killpg(os.getpgid(self.secondary_process_demod.pid), signal.SIGTERM)
|
||||
# drain any leftover data to free file descriptors
|
||||
self.secondary_process_demod.communicate()
|
||||
self.secondary_process_demod = None
|
||||
except ProcessLookupError:
|
||||
# been killed by something else, ignore
|
||||
pass
|
||||
self.secondary_processes_running = False
|
||||
|
||||
def get_secondary_demodulator(self):
|
||||
return self.secondary_demodulator
|
||||
|
||||
def set_secondary_fft_size(self, secondary_fft_size):
|
||||
if self.secondary_fft_size == secondary_fft_size:
|
||||
return
|
||||
self.secondary_fft_size = secondary_fft_size
|
||||
self.restart()
|
||||
|
||||
def set_audio_compression(self, what):
|
||||
if self.audio_compression == what:
|
||||
return
|
||||
self.audio_compression = what
|
||||
self.restart()
|
||||
|
||||
def get_audio_bytes_to_read(self):
|
||||
# desired latency: 5ms
|
||||
# uncompressed audio has 16 bits = 2 bytes per sample
|
||||
base = self.output_rate * 0.005 * 2
|
||||
# adpcm compresses the bitstream by 4
|
||||
if self.audio_compression == "adpcm":
|
||||
base = base / 4
|
||||
return int(base)
|
||||
|
||||
def set_fft_compression(self, what):
|
||||
if self.fft_compression == what:
|
||||
return
|
||||
self.fft_compression = what
|
||||
self.restart()
|
||||
|
||||
def get_fft_bytes_to_read(self):
|
||||
if self.fft_compression == "none":
|
||||
return self.fft_size * 4
|
||||
if self.fft_compression == "adpcm":
|
||||
return int((self.fft_size / 2) + (10 / 2))
|
||||
|
||||
def get_secondary_fft_bytes_to_read(self):
|
||||
if self.fft_compression == "none":
|
||||
return self.secondary_fft_size * 4
|
||||
if self.fft_compression == "adpcm":
|
||||
return (self.secondary_fft_size / 2) + (10 / 2)
|
||||
|
||||
def set_samp_rate(self, samp_rate):
|
||||
self.samp_rate = samp_rate
|
||||
self.calculate_decimation()
|
||||
if self.running:
|
||||
self.restart()
|
||||
|
||||
def calculate_decimation(self):
|
||||
(self.decimation, self.last_decimation) = self.get_decimation(self.samp_rate, self.get_audio_rate())
|
||||
|
||||
def get_decimation(self, input_rate, output_rate):
|
||||
if output_rate <= 0:
|
||||
raise ValueError("invalid output rate: {rate}".format(rate=output_rate))
|
||||
decimation = 1
|
||||
target_rate = output_rate
|
||||
# wideband fm has a much higher frequency deviation (75kHz).
|
||||
# we cannot cover this if we immediately decimate to the sample rate the audio will have later on, so we need
|
||||
# to compensate here.
|
||||
if self.get_demodulator() == "wfm" and output_rate < 200000:
|
||||
target_rate = 200000
|
||||
while input_rate / (decimation + 1) >= target_rate:
|
||||
decimation += 1
|
||||
fraction = float(input_rate / decimation) / output_rate
|
||||
return decimation, fraction
|
||||
|
||||
def if_samp_rate(self):
|
||||
return self.samp_rate / self.decimation
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_output_rate(self):
|
||||
return self.output_rate
|
||||
|
||||
def get_hd_output_rate(self):
|
||||
return self.hd_output_rate
|
||||
|
||||
def get_audio_rate(self):
|
||||
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isDrm():
|
||||
return 48000
|
||||
elif self.isWsjtMode() or self.isJs8():
|
||||
return 12000
|
||||
elif self.isFreeDV():
|
||||
return 8000
|
||||
elif self.isHdAudio():
|
||||
return self.get_hd_output_rate()
|
||||
return self.get_output_rate()
|
||||
|
||||
def isDigitalVoice(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_demodulator()
|
||||
return demodulator in ["dmr", "dstar", "nxdn", "ysf", "m17"]
|
||||
|
||||
def isWsjtMode(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]
|
||||
|
||||
def isJs8(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator == "js8"
|
||||
|
||||
def isPacket(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator == "packet"
|
||||
|
||||
def isPocsag(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator == "pocsag"
|
||||
|
||||
def isFreeDV(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_demodulator()
|
||||
return demodulator == "freedv"
|
||||
|
||||
def isHdAudio(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_demodulator()
|
||||
return demodulator == "wfm"
|
||||
|
||||
def isDrm(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_demodulator()
|
||||
return demodulator == "drm"
|
||||
|
||||
def set_output_rate(self, output_rate):
|
||||
if self.output_rate == output_rate:
|
||||
return
|
||||
self.output_rate = output_rate
|
||||
self.calculate_decimation()
|
||||
self.restart()
|
||||
|
||||
def set_hd_output_rate(self, hd_output_rate):
|
||||
if self.hd_output_rate == hd_output_rate:
|
||||
return
|
||||
self.hd_output_rate = hd_output_rate
|
||||
self.calculate_decimation()
|
||||
self.restart()
|
||||
|
||||
def set_demodulator(self, demodulator):
|
||||
if demodulator in ["usb", "lsb", "cw"]:
|
||||
demodulator = "ssb"
|
||||
if self.demodulator == demodulator:
|
||||
return
|
||||
self.demodulator = demodulator
|
||||
self.calculate_decimation()
|
||||
self.restart()
|
||||
|
||||
def get_demodulator(self):
|
||||
return self.demodulator
|
||||
|
||||
def set_fft_size(self, fft_size):
|
||||
if self.fft_size == fft_size:
|
||||
return
|
||||
self.fft_size = fft_size
|
||||
self.restart()
|
||||
|
||||
def set_fft_fps(self, fft_fps):
|
||||
self.fft_fps = fft_fps
|
||||
self.restart()
|
||||
|
||||
def set_fft_averages(self, fft_averages):
|
||||
self.fft_averages = fft_averages
|
||||
self.restart()
|
||||
|
||||
def fft_block_size(self):
|
||||
if self.fft_averages == 0:
|
||||
return self.samp_rate / self.fft_fps
|
||||
else:
|
||||
return self.samp_rate / self.fft_fps / self.fft_averages
|
||||
|
||||
def set_offset_freq(self, offset_freq):
|
||||
if offset_freq is None:
|
||||
return
|
||||
self.offset_freq = offset_freq
|
||||
if self.running:
|
||||
self.pipes["shift_pipe"].write("%g\n" % (-float(self.offset_freq) / self.samp_rate))
|
||||
|
||||
def set_center_freq(self, center_freq):
|
||||
# dsp only needs to know this to be able to pass it to decoders in the form of get_operating_freq()
|
||||
self.center_freq = center_freq
|
||||
|
||||
def get_operating_freq(self):
|
||||
return self.center_freq + self.offset_freq
|
||||
|
||||
def set_bandpass(self, bandpass):
|
||||
self.set_bpf(bandpass.low_cut, bandpass.high_cut)
|
||||
|
||||
def set_bpf(self, low_cut, high_cut):
|
||||
self.low_cut = low_cut
|
||||
self.high_cut = high_cut
|
||||
if self.running:
|
||||
self.pipes["bpf_pipe"].write(
|
||||
"%g %g\n" % (float(self.low_cut) / self.if_samp_rate(), float(self.high_cut) / self.if_samp_rate())
|
||||
)
|
||||
|
||||
def get_bpf(self):
|
||||
return [self.low_cut, self.high_cut]
|
||||
|
||||
def convertToLinear(self, db):
|
||||
return float(math.pow(10, db / 10))
|
||||
|
||||
def set_squelch_level(self, squelch_level):
|
||||
self.squelch_level = squelch_level
|
||||
# no squelch required on digital voice modes
|
||||
actual_squelch = (
|
||||
-150
|
||||
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV()
|
||||
else self.squelch_level
|
||||
)
|
||||
if self.running:
|
||||
self.pipes["squelch_pipe"].write("%g\n" % (self.convertToLinear(actual_squelch)))
|
||||
|
||||
def set_unvoiced_quality(self, q):
|
||||
self.unvoiced_quality = q
|
||||
self.restart()
|
||||
|
||||
def get_unvoiced_quality(self):
|
||||
return self.unvoiced_quality
|
||||
|
||||
def set_dmr_filter(self, filter):
|
||||
if self.has_pipe("dmr_control_pipe"):
|
||||
self.pipes["dmr_control_pipe"].write("{0}\n".format(filter))
|
||||
|
||||
def set_wfm_deemphasis_tau(self, tau):
|
||||
if self.wfm_deemphasis_tau == tau:
|
||||
return
|
||||
self.wfm_deemphasis_tau = tau
|
||||
self.restart()
|
||||
|
||||
def ddc_transition_bw(self):
|
||||
return self.ddc_transition_bw_rate * (self.if_samp_rate() / float(self.samp_rate))
|
||||
|
||||
def try_create_pipes(self, pipe_names, command_base):
|
||||
for pipe_name, pipe_type in pipe_names.items():
|
||||
if self.has_pipe(pipe_name):
|
||||
logger.warning("{pipe_name} is still in use", pipe_name=pipe_name)
|
||||
self.pipes[pipe_name].close()
|
||||
if "{" + pipe_name + "}" in command_base:
|
||||
p = self.pipe_base_path + pipe_name
|
||||
encoding = None
|
||||
# TODO make digiham output unicode and then change this here
|
||||
# the whole pipe enoding feature onlye exists because of this
|
||||
if pipe_name == "meta_pipe":
|
||||
encoding = "cp437"
|
||||
self.pipes[pipe_name] = Pipe.create(p, pipe_type, encoding=encoding)
|
||||
else:
|
||||
self.pipes[pipe_name] = None
|
||||
|
||||
def has_pipe(self, name):
|
||||
return name in self.pipes and self.pipes[name] is not None
|
||||
|
||||
def try_delete_pipes(self, pipe_names):
|
||||
for pipe_name in pipe_names:
|
||||
if self.has_pipe(pipe_name):
|
||||
self.pipes[pipe_name].close()
|
||||
self.pipes[pipe_name] = None
|
||||
|
||||
def try_create_configs(self, command):
|
||||
if "{direwolf_config}" in command:
|
||||
self.direwolf_config_path = "{tmp_dir}/openwebrx_direwolf_{myid}.conf".format(
|
||||
tmp_dir=self.temporary_directory, myid=id(self)
|
||||
)
|
||||
self.direwolf_config = DirewolfConfig()
|
||||
self.direwolf_config.wire(self)
|
||||
file = open(self.direwolf_config_path, "w")
|
||||
file.write(self.direwolf_config.getConfig(self.is_service))
|
||||
file.close()
|
||||
else:
|
||||
self.direwolf_config = None
|
||||
self.direwolf_config_path = None
|
||||
|
||||
def try_delete_configs(self):
|
||||
if self.direwolf_config is not None:
|
||||
self.direwolf_config.unwire(self)
|
||||
self.direwolf_config = None
|
||||
if self.direwolf_config_path is not None:
|
||||
try:
|
||||
os.unlink(self.direwolf_config_path)
|
||||
except FileNotFoundError:
|
||||
# result suits our expectations. fine :)
|
||||
pass
|
||||
except Exception:
|
||||
logger.exception("try_delete_configs()")
|
||||
self.direwolf_config_path = None
|
||||
|
||||
def onConfigChanged(self):
|
||||
self.restart()
|
||||
|
||||
def start(self):
|
||||
with self.modification_lock:
|
||||
if self.running:
|
||||
return
|
||||
self.running = True
|
||||
|
||||
command_base = " | ".join(self.chain(self.demodulator))
|
||||
|
||||
# create control pipes for csdr
|
||||
self.try_create_pipes(self.pipe_names, command_base)
|
||||
|
||||
# send initial config through the pipes
|
||||
if self.has_pipe("bpf_pipe"):
|
||||
self.set_bpf(self.low_cut, self.high_cut)
|
||||
if self.has_pipe("shift_pipe"):
|
||||
self.set_offset_freq(self.offset_freq)
|
||||
if self.has_pipe("squelch_pipe"):
|
||||
self.set_squelch_level(self.squelch_level)
|
||||
if self.has_pipe("dmr_control_pipe"):
|
||||
self.set_dmr_filter(3)
|
||||
|
||||
# run the command
|
||||
command = command_base.format(
|
||||
bpf_pipe=self.pipes["bpf_pipe"],
|
||||
shift_pipe=self.pipes["shift_pipe"],
|
||||
squelch_pipe=self.pipes["squelch_pipe"],
|
||||
smeter_pipe=self.pipes["smeter_pipe"],
|
||||
meta_pipe=self.pipes["meta_pipe"],
|
||||
iqtee_pipe=self.pipes["iqtee_pipe"],
|
||||
iqtee2_pipe=self.pipes["iqtee2_pipe"],
|
||||
dmr_control_pipe=self.pipes["dmr_control_pipe"],
|
||||
decimation=self.decimation,
|
||||
last_decimation=self.last_decimation,
|
||||
fft_size=self.fft_size,
|
||||
fft_block_size=self.fft_block_size(),
|
||||
fft_averages=self.fft_averages,
|
||||
bpf_transition_bw=float(self.bpf_transition_bw) / self.if_samp_rate(),
|
||||
ddc_transition_bw=self.ddc_transition_bw(),
|
||||
flowcontrol=int(self.samp_rate * 2),
|
||||
start_bufsize=self.base_bufsize * self.decimation,
|
||||
nc_port=self.nc_port,
|
||||
output_rate=self.get_output_rate(),
|
||||
smeter_report_every=int(self.if_samp_rate() / 6000),
|
||||
unvoiced_quality=self.get_unvoiced_quality(),
|
||||
audio_rate=self.get_audio_rate(),
|
||||
wfm_deemphasis_tau=self.wfm_deemphasis_tau,
|
||||
)
|
||||
|
||||
logger.debug("Command = %s", command)
|
||||
|
||||
out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL
|
||||
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True)
|
||||
|
||||
def watch_thread():
|
||||
rc = self.process.wait()
|
||||
logger.debug("dsp thread ended with rc=%d", rc)
|
||||
if rc == 0 and self.running and not self.modification_lock.locked():
|
||||
logger.debug("restarting since rc = 0, self.running = true, and no modification")
|
||||
self.restart()
|
||||
|
||||
threading.Thread(target=watch_thread, name="csdr_watch_thread").start()
|
||||
|
||||
audio_type = "hd_audio" if self.isHdAudio() else "audio"
|
||||
if self.output.supports_type(audio_type):
|
||||
self.output.send_output(
|
||||
audio_type,
|
||||
partial(
|
||||
self.process.stdout.read,
|
||||
self.get_fft_bytes_to_read() if self.demodulator == "fft" else self.get_audio_bytes_to_read(),
|
||||
),
|
||||
)
|
||||
|
||||
self.start_secondary_demodulator()
|
||||
|
||||
if self.has_pipe("smeter_pipe"):
|
||||
|
||||
def read_smeter():
|
||||
raw = self.pipes["smeter_pipe"].readline()
|
||||
if len(raw) == 0:
|
||||
return None
|
||||
else:
|
||||
return float(raw.rstrip("\n"))
|
||||
|
||||
self.output.send_output("smeter", read_smeter)
|
||||
if self.has_pipe("meta_pipe"):
|
||||
|
||||
def read_meta():
|
||||
raw = self.pipes["meta_pipe"].readline()
|
||||
if len(raw) == 0:
|
||||
return None
|
||||
else:
|
||||
return raw.rstrip("\n")
|
||||
|
||||
self.output.send_output("meta", read_meta)
|
||||
|
||||
def stop(self):
|
||||
with self.modification_lock:
|
||||
self.running = False
|
||||
if self.process is not None:
|
||||
try:
|
||||
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
|
||||
# drain any leftover data to free file descriptors
|
||||
self.process.communicate()
|
||||
self.process = None
|
||||
except ProcessLookupError:
|
||||
# been killed by something else, ignore
|
||||
pass
|
||||
self.stop_secondary_demodulator()
|
||||
|
||||
self.try_delete_pipes(self.pipe_names)
|
||||
self.try_delete_configs()
|
||||
|
||||
def restart(self):
|
||||
if not self.running:
|
||||
return
|
||||
self.stop()
|
||||
self.start()
|
@ -1,36 +0,0 @@
|
||||
import threading
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Output(object):
|
||||
def send_output(self, t, read_fn):
|
||||
if not self.supports_type(t):
|
||||
# TODO rewrite the output mechanism in a way that avoids producing unnecessary data
|
||||
logger.warning("dumping output of type %s since it is not supported.", t)
|
||||
threading.Thread(target=self.pump(read_fn, lambda x: None), name="csdr_pump_thread").start()
|
||||
return
|
||||
self.receive_output(t, read_fn)
|
||||
|
||||
def receive_output(self, t, read_fn):
|
||||
pass
|
||||
|
||||
def pump(self, read, write):
|
||||
def copy():
|
||||
run = True
|
||||
while run:
|
||||
data = None
|
||||
try:
|
||||
data = read()
|
||||
except ValueError:
|
||||
pass
|
||||
if data is None or (isinstance(data, bytes) and len(data) == 0):
|
||||
run = False
|
||||
else:
|
||||
write(data)
|
||||
|
||||
return copy
|
||||
|
||||
def supports_type(self, t):
|
||||
return True
|
156
csdr/pipe.py
@ -1,156 +0,0 @@
|
||||
import os
|
||||
import select
|
||||
import time
|
||||
import threading
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Pipe(object):
|
||||
READ = "r"
|
||||
WRITE = "w"
|
||||
NONE = None
|
||||
|
||||
@staticmethod
|
||||
def create(path, t, encoding=None):
|
||||
if t == Pipe.READ:
|
||||
return ReadingPipe(path, encoding=encoding)
|
||||
elif t == Pipe.WRITE:
|
||||
return WritingPipe(path, encoding=encoding)
|
||||
elif t == Pipe.NONE:
|
||||
return Pipe(path, None, encoding=encoding)
|
||||
|
||||
def __init__(self, path, direction, encoding=None):
|
||||
self.doOpen = True
|
||||
self.path = "{base}_{myid}".format(base=path, myid=id(self))
|
||||
self.direction = direction
|
||||
self.encoding = encoding
|
||||
self.file = None
|
||||
os.mkfifo(self.path)
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
this method opens the file descriptor with an added O_NONBLOCK flag. This gives us a special behaviour for
|
||||
FIFOS, when they are not opened by the opposing side:
|
||||
|
||||
- opening a pipe for writing will throw an OSError with errno = 6 (ENXIO). This is handled specially in the
|
||||
WritingPipe class.
|
||||
- opening a pipe for reading will pass through this method instantly, even if the opposing end has not been
|
||||
opened yet, but the resulting file descriptor will behave as if O_NONBLOCK is set (even if we remove it
|
||||
immediately here), resulting in empty reads until data is available. This is handled specially in the
|
||||
ReadingPipe class.
|
||||
"""
|
||||
|
||||
def opener(path, flags):
|
||||
fd = os.open(path, flags | os.O_NONBLOCK)
|
||||
os.set_blocking(fd, True)
|
||||
return fd
|
||||
|
||||
self.file = open(self.path, self.direction, encoding=self.encoding, opener=opener)
|
||||
|
||||
def close(self):
|
||||
self.doOpen = False
|
||||
try:
|
||||
if self.file is not None:
|
||||
self.file.close()
|
||||
os.unlink(self.path)
|
||||
except FileNotFoundError:
|
||||
# it seems like we keep calling this twice. no idea why, but we don't need the resulting error.
|
||||
pass
|
||||
except Exception:
|
||||
logger.exception("Pipe.close()")
|
||||
|
||||
def __str__(self):
|
||||
return self.path
|
||||
|
||||
|
||||
class WritingPipe(Pipe):
|
||||
def __init__(self, path, encoding=None):
|
||||
self.queue = []
|
||||
self.queueLock = threading.Lock()
|
||||
super().__init__(path, "w", encoding=encoding)
|
||||
self.open()
|
||||
|
||||
def open_and_dequeue(self):
|
||||
"""
|
||||
This method implements a retry loop that can be interrupted in case the Pipe gets shutdown before actually
|
||||
being connected.
|
||||
|
||||
After the pipe is opened successfully, all data that has been queued is sent in the order it was passed into
|
||||
write().
|
||||
"""
|
||||
retries = 0
|
||||
|
||||
while self.file is None and self.doOpen and retries < 10:
|
||||
try:
|
||||
super().open()
|
||||
except OSError as error:
|
||||
# ENXIO = FIFO has not been opened for reading
|
||||
if error.errno == 6:
|
||||
time.sleep(0.1)
|
||||
retries += 1
|
||||
else:
|
||||
raise
|
||||
|
||||
# if doOpen is false, opening has been canceled, so no warning in that case.
|
||||
if self.file is None:
|
||||
if self.doOpen:
|
||||
logger.warning("could not open FIFO %s", self.path)
|
||||
return
|
||||
|
||||
with self.queueLock:
|
||||
for i in self.queue:
|
||||
self.file.write(i)
|
||||
self.file.flush()
|
||||
self.queue = None
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
This sends the opening operation off to a background thread. If we were to block the thread here, another pipe
|
||||
may be waiting in the queue to be opened on the opposing side, resulting in a deadlock
|
||||
"""
|
||||
threading.Thread(target=self.open_and_dequeue, name="csdr_pipe_thread").start()
|
||||
|
||||
def write(self, data):
|
||||
"""
|
||||
This method queues all data to be written until the file is actually opened. As soon as a file is available,
|
||||
it becomes a passthrough.
|
||||
"""
|
||||
if self.file is None:
|
||||
with self.queueLock:
|
||||
self.queue.append(data)
|
||||
return
|
||||
r = self.file.write(data)
|
||||
self.file.flush()
|
||||
return r
|
||||
|
||||
|
||||
class ReadingPipe(Pipe):
|
||||
def __init__(self, path, encoding=None):
|
||||
super().__init__(path, "r", encoding=encoding)
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
This method implements an interruptible loop that waits for the file descriptor to be opened and the first
|
||||
batch of data coming in using repeated select() calls.
|
||||
:return:
|
||||
"""
|
||||
if not self.doOpen:
|
||||
return
|
||||
super().open()
|
||||
while self.doOpen:
|
||||
(read, _, _) = select.select([self.file], [], [], 1)
|
||||
if self.file in read:
|
||||
break
|
||||
|
||||
def read(self):
|
||||
if self.file is None:
|
||||
self.open()
|
||||
return self.file.read()
|
||||
|
||||
def readline(self):
|
||||
if self.file is None:
|
||||
self.open()
|
||||
return self.file.readline()
|
207
debian/changelog
vendored
@ -1,207 +0,0 @@
|
||||
openwebrx (1.0.0) buster hirsute; urgency=low
|
||||
* Introduced `squelch_auto_margin` config option that allows configuring the
|
||||
auto squelch level
|
||||
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
||||
with the new connectors
|
||||
* Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X
|
||||
2.3) and Q65 (only available with WSJT-X 2.4)
|
||||
* Added support for demodulating M17 digital voice signals using
|
||||
m17-cxx-demod
|
||||
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
||||
wsprnet.org
|
||||
* Add some basic filtering capabilities to the map
|
||||
* New arguments to the `openwebrx` command-line to facilitate the
|
||||
administration of users (try `openwebrx admin`)
|
||||
* New command-line tool `openwebrx-admin` that facilitates the
|
||||
administration of users
|
||||
* Default bandwidth changes:
|
||||
- "WFM" changed to 150kHz
|
||||
- "Packet" (APRS) changed to 12.5kHz
|
||||
* Configuration rework:
|
||||
- New: fully web-based configuration interface
|
||||
- System configuration parameters have been moved to a new, separate
|
||||
`openwebrx.conf` file
|
||||
- Remaining parameters are now editable in the web configuration
|
||||
- Existing `config_webrx.py` files will still be read, but changes made in
|
||||
the web configuration will be written to a new storage system
|
||||
- Added upload of avatar and panorama image via web configuration
|
||||
* New devices supported:
|
||||
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
||||
- R&S devices using the EB200 or Ammos protocols
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Thu, 06 May 2021 17:22:00 +0000
|
||||
|
||||
openwebrx (0.20.3) buster focal; urgency=low
|
||||
|
||||
* Fix a compatibility issue with python versions <= 3.6
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Tue, 26 Jan 2021 15:28:00 +0000
|
||||
|
||||
openwebrx (0.20.2) buster focal; urgency=high
|
||||
|
||||
* Fix a security problem that allowed arbitrary commands to be executed on
|
||||
the receiver (See github issue #215:
|
||||
https://github.com/jketterl/openwebrx/issues/215)
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sun, 24 Jan 2021 22:50:00 +0000
|
||||
|
||||
openwebrx (0.20.1) buster focal; urgency=low
|
||||
|
||||
* Remove broken OSM map fallback
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Mon, 30 Nov 2020 17:29:00 +0000
|
||||
|
||||
openwebrx (0.20.0) buster focal; urgency=low
|
||||
|
||||
* Added the ability to sign multiple keys in a single request, thus enabling
|
||||
multiple users to claim a single receiver on receiverbook.de
|
||||
* Fixed file descriptor leaks to prevent "too many open files" errors
|
||||
* Add new demodulator chain for FreeDV
|
||||
* Added new HD audio streaming mode along with a new WFM demodulator
|
||||
* Reworked AGC code for better results in AM, SSB and digital modes
|
||||
* Added support for demodulation of "Digital Radio Mondiale" (DRM) broadcast
|
||||
using the "dream" decoder.
|
||||
* New default waterfall color scheme
|
||||
* Prototype of a continuous automatic waterfall calibration mode
|
||||
* New devices supported:
|
||||
- FunCube Dongle Pro+ (`"type": "fcdpp"`)
|
||||
- Support for connections to rtl_tcp (`"type": "rtl_tcp"`)
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sun, 11 Oct 2020 13:02:00 +0000
|
||||
|
||||
openwebrx (0.19.1) buster focal; urgency=low
|
||||
|
||||
* Added ability to authenticate receivers with listing sites using
|
||||
"receiver id" tokens
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sat, 13 Jun 2020 16:46:00 +0000
|
||||
|
||||
openwebrx (0.19.0) buster focal; urgency=low
|
||||
* Fix direwolf connection setup by implementing a retry loop
|
||||
* Pass direct sampling mode changes for rtl_sdr_soapy to owrx_connector
|
||||
* OSM maps instead of Google when google_maps_api_key is not set (thanks
|
||||
@jquagga)
|
||||
* Improved logic to pass parameters to soapy devices.
|
||||
- `rtl_sdr_soapy`: added support for `bias_tee`
|
||||
- `sdrplay`: added support for `bias_tee`, `rf_notch` and `dab_notch`
|
||||
- `airspy`: added support for `bitpack`
|
||||
* Added support for Perseus-SDR devices, (thanks @amontefusco)
|
||||
* Property System has been rewritten so that defaults on sdr behave as
|
||||
expected
|
||||
* Waterfall range auto-adjustment now only takes the center 80% of the
|
||||
spectrum into account, which should work better with SDRs that oversample
|
||||
or have rather flat filter curves towards the spectrum edges
|
||||
* Bugfix for negative network usage
|
||||
* FiFi SDR: prevent arecord from shutting down after 2GB of data has been
|
||||
sent
|
||||
* Added support for bias tee control on rtl_sdr devices
|
||||
* All connector driven SDRs now support `"rf_gain": "auto"` to enable AGC
|
||||
* `rtl_sdr` type now also supports the `direct_sampling` option
|
||||
* Added decoding implementation for for digimode "JS8Call" (requires an
|
||||
installation of js8call and the js8py library)
|
||||
* Reorganization of the frontend demodulator code
|
||||
* Improve receiver load time by concatenating javascript assets
|
||||
* HackRF support is now based on SoapyHackRF
|
||||
* Removed sdr.hu server listing support since the site has been shut down
|
||||
* Added support for Radioberry 2 Rasbperry Pi SDR Cape
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Mon, 01 Jun 2020 17:02:00 +0000
|
||||
|
||||
openwebrx (0.18.0) buster; urgency=low
|
||||
|
||||
* Compression, resampling and filtering in the frontend have been rewritten
|
||||
in javascript, sdr.js has been removed
|
||||
* Decoding of Pocsag modulation is now possible
|
||||
* Removed the 3D waterfall since it had no real application and required ~1MB
|
||||
of javascript code to be downloaded
|
||||
* Improved the frontend handling of the "too many users" scenario
|
||||
* PSK63 digimode is now available (same decoding pipeline as PSK31, but with
|
||||
adopted parameters)
|
||||
* The frequency can now be manipulated with the mousewheel, which should
|
||||
allow the user to tune more precise. The tuning step size is determined by
|
||||
the digit the mouse cursor is hovering over.
|
||||
* Clicking on the frequency now opens an input for direct frequency selection
|
||||
* URL hashes have been fixed and improved: They are now updated
|
||||
automatically, so a shared URL will include frequency and demodulator,
|
||||
which allows for improved sharing and linking.
|
||||
* New daylight scheduler for background decoding, allows profiles to be
|
||||
selected by local sunrise / sunset times
|
||||
* The owrx_connector is now the default way of communicating with sdr
|
||||
devices. The old sdr types have been replaced, all `_connector` suffixes on
|
||||
the type must be removed!
|
||||
* The sources have been refactored, making it a lot easier to add support for
|
||||
other devices
|
||||
* SDR device failure handling has been improved, including user feedback
|
||||
* New devices supported:
|
||||
* wsjt-x updated to 2.1.2
|
||||
* The rtl_tcp compatibility mode of the owrx_connector is now configurable
|
||||
using the `rtltcp_compat` flag
|
||||
* explicit device filter for soapy devices for multi-device setups
|
||||
* compatibility fixes for safari browsers (ios and mac)
|
||||
* Offset tuning using the `lfo_offset` has been reworked in a way that
|
||||
`center_freq` has to be set to the frequency you actually want to listen
|
||||
to. If you're using an `lfo_offset` already, you will probably need to
|
||||
change its sign.
|
||||
* `initial_squelch_level` can now be set on each profile.
|
||||
* Part of the frontend code has been reworked
|
||||
- Audio buffer minimums have been completely stripped. As a result, you
|
||||
should get better latency. Unfortunately, this also means there will be
|
||||
some skipping when audio starts.
|
||||
- Now also supports AudioWorklets (for those browser that have it).
|
||||
- Mousewheel controls for the receiver sliders
|
||||
* Error handling for failed SDR devices
|
||||
* One of the most-requested features is finally coming to OpenWebRX:
|
||||
Bookmarks (sometimes also referred to as labels).
|
||||
There's two kinds of bookmarks available:
|
||||
- Serverside bookmarks that are set up by the receiver administrator.
|
||||
Check the file `bookmarks.json` for examples!
|
||||
- Clientside bookmarks which every user can store for themselves. They are
|
||||
stored in the browser's localStorage.
|
||||
* Automatic reporting of spots to [pskreporter](https://pskreporter.info/) is
|
||||
now possible. Please have a look at the configuration on how to set it up.
|
||||
* Websocket communication has been overhauled in large parts. It should now
|
||||
be more reliable, and failing connections should now have no impact on
|
||||
other users.
|
||||
* Profile scheduling allows to set up band-hopping if you are running
|
||||
background services.
|
||||
* APRS now has the ability to show symbols on the map, if a corresponding
|
||||
symbol set has been installed. Check the config!
|
||||
* Debug logging has been disabled in a handful of modules, expect vastly
|
||||
reduced output on the shell.
|
||||
* New set of APRS-related features
|
||||
- Decode Packet transmissions using direwolf (1k2 only for now)
|
||||
- APRS packets are mostly decoded and shown both in a new panel and on the
|
||||
map
|
||||
- APRS is also available as a background service
|
||||
- direwolfs I-gate functionality can be enabled, which allows your receiver
|
||||
to work as a receive-only I-gate for the APRS network in the background
|
||||
* Demodulation for background services has been optimized to use less total
|
||||
bandwidth, saving CPU
|
||||
* More metrics have been added; they can be used together with collectd and
|
||||
its curl_json plugin for now, with some limitations.
|
||||
* New bandplan feature, the first thing visible is the "dial" indicator that
|
||||
brings you right to the dial frequency for digital modes
|
||||
* fixed some bugs in the websocket communication which broke the map
|
||||
* WSJT-X integration (FT8, FT4, WSPR, JT65, JT9 using wsjt-x demodulators)
|
||||
* New Map Feature that shows both decoded grid squares from FT8 and Locations
|
||||
decoded from YSF digital voice
|
||||
* New Feature report that will show what functionality is available
|
||||
* major rework on the openwebrx core
|
||||
* Support of multiple SDR devices simultaneously
|
||||
* Support for multiple profiles per SDR that allow the user to listen to
|
||||
different frequencies
|
||||
* Support for digital voice decoding
|
||||
* Feature detection that will disable functionality when dependencies are not
|
||||
available (if you're missing the digital
|
||||
buttons, this is probably why)
|
||||
* Support added for the following SDR sources:
|
||||
- LimeSDR (`"type": "lime_sdr"`)
|
||||
- PlutoSDR (`"type": "pluto_sdr"`)
|
||||
- RTL_SDR via Soapy (`"type": "rtl_sdr_soapy"`) on special request to allow
|
||||
use of the direct sampling mode
|
||||
- SoapyRemote (`"type": "soapy_remote"`)
|
||||
- FiFiSDR (`"type": "fifi_sdr"`)
|
||||
- airspyhf devices (Airspy HF+ / Discovery) (`"type": "airspyhf"`)
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Tue, 18 Feb 2020 20:09:00 +0000
|
1
debian/compat
vendored
@ -1 +0,0 @@
|
||||
10
|
16
debian/control
vendored
@ -1,16 +0,0 @@
|
||||
Source: openwebrx
|
||||
Maintainer: Jakob Ketterl <jakob.ketterl@gmx.de>
|
||||
Section: hamradio
|
||||
Priority: optional
|
||||
Standards-Version: 4.2.0
|
||||
Build-Depends: debhelper (>= 11), dh-python, python3-all (>= 3.5), python3-setuptools
|
||||
Homepage: https://www.openwebrx.de/
|
||||
Vcs-Browser: https://github.com/jketterl/openwebrx
|
||||
Vcs-Git: https://github.com/jketterl/openwebrx.git
|
||||
|
||||
Package: openwebrx
|
||||
Architecture: all
|
||||
Depends: adduser, python3 (>= 3.5), python3-pkg-resources, csdr (>= 0.17), netcat, owrx-connector (>= 0.4), soapysdr-tools, python3-js8py (>= 0.1), ${python3:Depends}, ${misc:Depends}
|
||||
Recommends: digiham (>= 0.4), dsd (>= 1.7), sox, direwolf (>= 1.4), wsjtx, runds-connector, hpsdrconnector, aprs-symbols, m17-demod, js8call
|
||||
Description: multi-user web sdr
|
||||
Open source, multi-user SDR receiver with a web interface
|
8
debian/openwebrx.config
vendored
@ -1,8 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
db_get openwebrx/admin_user_configured
|
||||
if [ "${1:-}" = "reconfigure" ] || [ "${RET}" != true ]; then
|
||||
db_input high openwebrx/admin_user_password || true
|
||||
db_go
|
||||
fi
|
1
debian/openwebrx.dirs
vendored
@ -1 +0,0 @@
|
||||
/etc/openwebrx/openwebrx.conf.d
|
3
debian/openwebrx.install
vendored
@ -1,3 +0,0 @@
|
||||
bands.json etc/openwebrx/
|
||||
openwebrx.conf etc/openwebrx/
|
||||
systemd/openwebrx.service lib/systemd/system/
|
59
debian/openwebrx.postinst
vendored
@ -1,59 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OWRX_USER="openwebrx"
|
||||
OWRX_DATADIR="/var/lib/openwebrx"
|
||||
OWRX_USERS_FILE="${OWRX_DATADIR}/users.json"
|
||||
OWRX_SETTINGS_FILE="${OWRX_DATADIR}/settings.json"
|
||||
OWRX_BOOKMARKS_FILE="${OWRX_DATADIR}/bookmarks.json"
|
||||
|
||||
case "$1" in
|
||||
configure|reconfigure)
|
||||
adduser --system --group --no-create-home --home /nonexistent --quiet "${OWRX_USER}"
|
||||
usermod -aG plugdev openwebrx
|
||||
|
||||
# create OpenWebRX data directory and set the correct permissions
|
||||
if [ ! -d "${OWRX_DATADIR}" ] && [ ! -L "${OWRX_DATADIR}" ]; then mkdir "${OWRX_DATADIR}"; fi
|
||||
chown "${OWRX_USER}". ${OWRX_DATADIR}
|
||||
|
||||
# create empty config files now to avoid permission problems later
|
||||
if [ ! -e "${OWRX_USERS_FILE}" ]; then
|
||||
echo "[]" > "${OWRX_USERS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_USERS_FILE}"
|
||||
chmod 0600 "${OWRX_USERS_FILE}"
|
||||
fi
|
||||
|
||||
if [ ! -e "${OWRX_SETTINGS_FILE}" ]; then
|
||||
echo "{}" > "${OWRX_SETTINGS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_SETTINGS_FILE}"
|
||||
fi
|
||||
|
||||
if [ ! -e "${OWRX_BOOKMARKS_FILE}" ]; then
|
||||
touch "${OWRX_BOOKMARKS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_BOOKMARKS_FILE}"
|
||||
fi
|
||||
|
||||
db_get openwebrx/admin_user_password
|
||||
if [ ! -z "${RET}" ]; then
|
||||
if ! openwebrx admin --silent hasuser admin; then
|
||||
# create initial openwebrx user
|
||||
OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive adduser admin
|
||||
else
|
||||
# change existing user's password
|
||||
OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive resetpassword admin
|
||||
fi
|
||||
fi
|
||||
# remove password from debconf database
|
||||
db_unregister openwebrx/admin_user_password
|
||||
# set a marker that admin is configured to avoid future questions
|
||||
db_set openwebrx/admin_user_configured true
|
||||
;;
|
||||
*)
|
||||
echo "postinst called with unknown argument '$1'" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
8
debian/openwebrx.postrm
vendored
@ -1,8 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
|
||||
. /usr/share/debconf/confmodule
|
||||
db_purge
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
23
debian/openwebrx.templates
vendored
@ -1,23 +0,0 @@
|
||||
Template: openwebrx/admin_user_password
|
||||
Type: password
|
||||
Description: OpenWebRX "admin" user password:
|
||||
The system can create a user for the OpenWebRX web configuration interface for
|
||||
you. Using this user, you will be able to log into the "settings" area of
|
||||
OpenWebRX to configure your receiver conveniently through your browser.
|
||||
.
|
||||
The name of the created user will be "admin".
|
||||
.
|
||||
If you do not wish to create a web admin user right now, you can leave this
|
||||
empty for now. You can return to this prompt at a later time by running the
|
||||
command "sudo dpkg-reconfigure openwebrx".
|
||||
.
|
||||
You can also use the "openwebrx admin" command to create, delete or manage
|
||||
existing users. More information is available in by running the command
|
||||
"openwebrx admin --help".
|
||||
|
||||
Template: openwebrx/admin_user_configured
|
||||
Type: boolean
|
||||
Default: false
|
||||
Description: OpenWebRX "admin" user previously configured?
|
||||
Marker used internally by the config scripts to remember if an admin user has
|
||||
been created.
|
8
debian/rules
vendored
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
export PYBUILD_NAME=openwebrx
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild --with systemd
|
||||
|
||||
override_dh_strip_nondeterminism:
|
||||
dh_strip_nondeterminism -X.png
|
1
debian/source/format
vendored
@ -1 +0,0 @@
|
||||
3.0 (native)
|
97
docker.sh
@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ARCH=$(uname -m)
|
||||
IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-full openwebrx"
|
||||
ALL_ARCHS="x86_64 armv7l aarch64"
|
||||
TAG=${TAG:-"latest"}
|
||||
ARCHTAG="$TAG-$ARCH"
|
||||
|
||||
usage () {
|
||||
echo "Usage: ${0} [command]"
|
||||
echo "Available commands:"
|
||||
echo " help Show this usage information"
|
||||
echo " build Build all docker images"
|
||||
echo " push Push built docker images to the docker hub"
|
||||
echo " manifest Compile the docker hub manifest (combines arm and x86 tags into one)"
|
||||
echo " tag Tag a release"
|
||||
}
|
||||
|
||||
build () {
|
||||
# build the base images
|
||||
docker build --pull -t openwebrx-base:${ARCHTAG} -f docker/Dockerfiles/Dockerfile-base .
|
||||
docker build --build-arg ARCHTAG=${ARCHTAG} -t openwebrx-soapysdr-base:${ARCHTAG} -f docker/Dockerfiles/Dockerfile-soapysdr .
|
||||
|
||||
for image in ${IMAGES}; do
|
||||
i=${image:10}
|
||||
# "openwebrx" is a special image that gets tag-aliased later on
|
||||
if [[ ! -z "${i}" ]] ; then
|
||||
docker build --build-arg ARCHTAG=$ARCHTAG -t jketterl/${image}:${ARCHTAG} -f docker/Dockerfiles/Dockerfile-${i} .
|
||||
fi
|
||||
done
|
||||
|
||||
# tag openwebrx alias image
|
||||
docker tag jketterl/openwebrx-full:${ARCHTAG} jketterl/openwebrx:${ARCHTAG}
|
||||
}
|
||||
|
||||
push () {
|
||||
for image in ${IMAGES}; do
|
||||
docker push jketterl/$image:$ARCHTAG
|
||||
done
|
||||
}
|
||||
|
||||
manifest () {
|
||||
for image in ${IMAGES}; do
|
||||
# there's no docker manifest rm command, and the create --amend does not work, so we have to clean up manually
|
||||
rm -rf "${HOME}/.docker/manifests/docker.io_jketterl_${image}-${TAG}"
|
||||
IMAGE_LIST=""
|
||||
for a in $ALL_ARCHS; do
|
||||
IMAGE_LIST="$IMAGE_LIST jketterl/$image:$TAG-$a"
|
||||
done
|
||||
docker manifest create jketterl/$image:$TAG $IMAGE_LIST
|
||||
docker manifest push --purge jketterl/$image:$TAG
|
||||
done
|
||||
}
|
||||
|
||||
tag () {
|
||||
if [[ -x ${1:-} || -z ${2:-} ]] ; then
|
||||
echo "Usage: ${0} tag [SRC_TAG] [TARGET_TAG]"
|
||||
return
|
||||
fi
|
||||
|
||||
local SRC_TAG=${1}
|
||||
local TARGET_TAG=${2}
|
||||
|
||||
for image in ${IMAGES}; do
|
||||
# there's no docker manifest rm command, and the create --amend does not work, so we have to clean up manually
|
||||
rm -rf "${HOME}/.docker/manifests/docker.io_jketterl_${image}-${TARGET_TAG}"
|
||||
IMAGE_LIST=""
|
||||
for a in ${ALL_ARCHS}; do
|
||||
docker pull jketterl/${image}:${SRC_TAG}-${a}
|
||||
docker tag jketterl/${image}:${SRC_TAG}-${a} jketterl/${image}:${TARGET_TAG}-${a}
|
||||
docker push jketterl/${image}:${TARGET_TAG}-${a}
|
||||
IMAGE_LIST="${IMAGE_LIST} jketterl/${image}:${TARGET_TAG}-${a}"
|
||||
done
|
||||
docker manifest create jketterl/${image}:${TARGET_TAG} ${IMAGE_LIST}
|
||||
docker manifest push --purge jketterl/${image}:${TARGET_TAG}
|
||||
docker pull jketterl/${image}:${TARGET_TAG}
|
||||
done
|
||||
}
|
||||
|
||||
case ${1:-} in
|
||||
build)
|
||||
build
|
||||
;;
|
||||
push)
|
||||
push
|
||||
;;
|
||||
manifest)
|
||||
manifest
|
||||
;;
|
||||
tag)
|
||||
tag ${@:2}
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-airspy.sh /
|
||||
RUN /install-dependencies-airspy.sh &&\
|
||||
rm /install-dependencies-airspy.sh
|
||||
|
||||
ADD . /opt/openwebrx
|
@ -1,26 +0,0 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
COPY docker/files/js8call/js8call-hamlib.patch \
|
||||
docker/files/wsjtx/wsjtx.patch \
|
||||
docker/files/wsjtx/wsjtx-hamlib.patch \
|
||||
docker/files/dream/dream.patch \
|
||||
docker/files/direwolf/direwolf-hamlib.patch \
|
||||
docker/scripts/install-dependencies.sh /
|
||||
RUN /install-dependencies.sh && \
|
||||
rm /install-dependencies.sh && \
|
||||
rm /*.patch
|
||||
COPY docker/scripts/install-owrx-tools.sh /
|
||||
RUN /install-owrx-tools.sh && \
|
||||
rm /install-owrx-tools.sh
|
||||
|
||||
ENTRYPOINT ["/init"]
|
||||
|
||||
WORKDIR /opt/openwebrx
|
||||
|
||||
VOLUME /etc/openwebrx
|
||||
VOLUME /var/lib/openwebrx
|
||||
|
||||
ENV S6_CMD_ARG0="/opt/openwebrx/docker/scripts/run.sh"
|
||||
CMD []
|
||||
|
||||
EXPOSE 8073
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-fcdpp.sh /
|
||||
RUN /install-dependencies-fcdpp.sh &&\
|
||||
rm /install-dependencies-fcdpp.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,30 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-*.sh \
|
||||
docker/files/sdrplay/install-lib.*.patch \
|
||||
docker/scripts/install-connectors.sh /
|
||||
|
||||
RUN /install-dependencies-rtlsdr.sh &&\
|
||||
/install-dependencies-soapysdr.sh &&\
|
||||
/install-dependencies-hackrf.sh &&\
|
||||
/install-dependencies-sdrplay.sh &&\
|
||||
/install-dependencies-airspy.sh &&\
|
||||
/install-dependencies-rtlsdr-soapy.sh &&\
|
||||
/install-dependencies-plutosdr.sh &&\
|
||||
/install-dependencies-limesdr.sh &&\
|
||||
/install-dependencies-soapyremote.sh &&\
|
||||
/install-dependencies-perseus.sh &&\
|
||||
/install-dependencies-fcdpp.sh &&\
|
||||
/install-dependencies-radioberry.sh &&\
|
||||
/install-dependencies-uhd.sh &&\
|
||||
/install-dependencies-hpsdr.sh &&\
|
||||
/install-connectors.sh &&\
|
||||
/install-dependencies-runds.sh &&\
|
||||
rm /install-dependencies-*.sh &&\
|
||||
rm /install-lib.*.patch && \
|
||||
rm /install-connectors.sh
|
||||
|
||||
COPY docker/files/services/sdrplay /etc/services.d/sdrplay
|
||||
|
||||
ADD . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-hackrf.sh /
|
||||
RUN /install-dependencies-hackrf.sh &&\
|
||||
rm /install-dependencies-hackrf.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,9 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-hpsdr.sh /
|
||||
|
||||
RUN /install-dependencies-hpsdr.sh &&\
|
||||
rm /install-dependencies-hpsdr.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-limesdr.sh /
|
||||
RUN /install-dependencies-limesdr.sh &&\
|
||||
rm /install-dependencies-limesdr.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-perseus.sh /
|
||||
RUN /install-dependencies-perseus.sh &&\
|
||||
rm /install-dependencies-perseus.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-plutosdr.sh /
|
||||
RUN /install-dependencies-plutosdr.sh &&\
|
||||
rm /install-dependencies-plutosdr.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-radioberry.sh /
|
||||
RUN /install-dependencies-radioberry.sh &&\
|
||||
rm /install-dependencies-radioberry.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,12 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-rtlsdr.sh \
|
||||
docker/scripts/install-connectors.sh /
|
||||
|
||||
RUN /install-dependencies-rtlsdr.sh &&\
|
||||
rm /install-dependencies-rtlsdr.sh &&\
|
||||
/install-connectors.sh &&\
|
||||
rm /install-connectors.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-rtlsdr-soapy.sh /
|
||||
RUN /install-dependencies-rtlsdr-soapy.sh &&\
|
||||
rm /install-dependencies-rtlsdr-soapy.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,9 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-connectors.sh /
|
||||
|
||||
RUN /install-connectors.sh &&\
|
||||
rm /install-connectors.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,12 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-connectors.sh \
|
||||
docker/scripts/install-dependencies-runds.sh /
|
||||
|
||||
RUN /install-connectors.sh &&\
|
||||
rm /install-connectors.sh && \
|
||||
/install-dependencies-runds.sh && \
|
||||
rm /install-dependencies-runds.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,12 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-sdrplay.sh \
|
||||
docker/files/sdrplay/install-lib.*.patch /
|
||||
RUN /install-dependencies-sdrplay.sh &&\
|
||||
rm /install-dependencies-sdrplay.sh &&\
|
||||
rm /install-lib.*.patch
|
||||
|
||||
COPY docker/files/services/sdrplay /etc/services.d/sdrplay
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-soapyremote.sh /
|
||||
RUN /install-dependencies-soapyremote.sh &&\
|
||||
rm /install-dependencies-soapyremote.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,9 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-soapysdr.sh \
|
||||
docker/scripts/install-connectors.sh /
|
||||
RUN /install-dependencies-soapysdr.sh &&\
|
||||
rm /install-dependencies-soapysdr.sh &&\
|
||||
/install-connectors.sh &&\
|
||||
rm /install-connectors.sh
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-uhd.sh /
|
||||
RUN /install-dependencies-uhd.sh &&\
|
||||
rm /install-dependencies-uhd.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,20 +0,0 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 9e710f5..da90b43 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -257,13 +257,8 @@ else()
|
||||
set(GPSD_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
-find_package(hamlib)
|
||||
-if(HAMLIB_FOUND)
|
||||
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_HAMLIB")
|
||||
-else()
|
||||
- set(HAMLIB_INCLUDE_DIRS "")
|
||||
- set(HAMLIB_LIBRARIES "")
|
||||
-endif()
|
||||
+set(HAMLIB_INCLUDE_DIRS "")
|
||||
+set(HAMLIB_LIBRARIES "")
|
||||
|
||||
if(LINUX)
|
||||
find_package(ALSA REQUIRED)
|
@ -1,96 +0,0 @@
|
||||
--- dream.pro.org 2020-09-04 22:51:51.579926191 +0200
|
||||
+++ dream.pro 2020-09-04 22:52:57.609434707 +0200
|
||||
@@ -70,9 +70,6 @@
|
||||
exists(/opt/local/include/speex/speex_preprocess.h) {
|
||||
CONFIG += speexdsp
|
||||
}
|
||||
- exists(/opt/local/include/hamlib/rig.h) {
|
||||
- CONFIG += hamlib
|
||||
- }
|
||||
contains(QT_VERSION, ^4\\.7.*) {
|
||||
QT += phonon opengl svg
|
||||
DEFINES -= QWT_NO_SVG
|
||||
@@ -138,12 +135,6 @@
|
||||
packagesExist(sndfile) {
|
||||
CONFIG += sndfile
|
||||
}
|
||||
- packagesExist(hamlib) {
|
||||
- CONFIG += hamlib
|
||||
- }
|
||||
- packagesExist(gpsd) {
|
||||
- CONFIG += gps
|
||||
- }
|
||||
packagesExist(pcap) {
|
||||
CONFIG += pcap
|
||||
}
|
||||
@@ -159,14 +150,6 @@
|
||||
exists(/usr/local/include/sndfile.h) {
|
||||
CONFIG += sndfile
|
||||
}
|
||||
- exists(/usr/include/hamlib/rig.h) | \
|
||||
- exists(/usr/local/include/hamlib/rig.h) {
|
||||
- CONFIG += hamlib
|
||||
- }
|
||||
- exists(/usr/include/gps.h) | \
|
||||
- exists(/usr/local/include/gps.h) {
|
||||
- CONFIG += gps
|
||||
- }
|
||||
exists(/usr/include/pcap.h) | \
|
||||
exists(/usr/local/include/pcap.h) {
|
||||
CONFIG += pcap
|
||||
@@ -194,9 +177,6 @@
|
||||
exists($$OUT_PWD/include/speex/speex_preprocess.h) {
|
||||
CONFIG += speexdsp
|
||||
}
|
||||
- exists($$OUT_PWD/include/hamlib/rig.h) {
|
||||
- CONFIG += hamlib
|
||||
- }
|
||||
exists($$OUT_PWD/include/pcap.h) {
|
||||
CONFIG += pcap
|
||||
}
|
||||
@@ -225,7 +205,7 @@
|
||||
LIBS += -lz
|
||||
}
|
||||
}
|
||||
-exists($$OUT_PWD/include/neaacdec.h) {
|
||||
+exists(/usr/include/neaacdec.h) {
|
||||
DEFINES += HAVE_LIBFAAD \
|
||||
USE_FAAD2_LIBRARY
|
||||
LIBS += -lfaad_drm
|
||||
@@ -257,11 +237,6 @@
|
||||
win32:LIBS += libspeexdsp.lib
|
||||
message("with libspeexdsp")
|
||||
}
|
||||
-gps {
|
||||
- DEFINES += HAVE_LIBGPS
|
||||
- unix:LIBS += -lgps
|
||||
- message("with gps")
|
||||
-}
|
||||
pcap {
|
||||
DEFINES += HAVE_LIBPCAP
|
||||
unix:LIBS += -lpcap
|
||||
@@ -269,24 +244,6 @@
|
||||
win32-g++:LIBS += -lwpcap -lpacket
|
||||
message("with pcap")
|
||||
}
|
||||
-hamlib {
|
||||
- DEFINES += HAVE_LIBHAMLIB
|
||||
- macx:LIBS += -framework IOKit
|
||||
- unix:LIBS += -lhamlib
|
||||
- win32:LIBS += libhamlib-2.lib
|
||||
- HEADERS += src/util/Hamlib.h
|
||||
- SOURCES += src/util/Hamlib.cpp
|
||||
- qt {
|
||||
- HEADERS += src/util-QT/Rig.h
|
||||
- SOURCES += src/util-QT/Rig.cpp
|
||||
- }
|
||||
- gui {
|
||||
- HEADERS += src/GUI-QT/RigDlg.h
|
||||
- SOURCES += src/GUI-QT/RigDlg.cpp
|
||||
- FORMS += RigDlg.ui
|
||||
- }
|
||||
- message("with hamlib")
|
||||
-}
|
||||
qwt {
|
||||
DEFINES += QWT_NO_SVG
|
||||
macx {
|
@ -1,151 +0,0 @@
|
||||
diff -ur js8call-orig/CMake/Modules/Findhamlib.cmake js8call/CMake/Modules/Findhamlib.cmake
|
||||
--- js8call-orig/CMake/Modules/Findhamlib.cmake 2020-07-22 18:14:18.014499840 +0200
|
||||
+++ js8call/CMake/Modules/Findhamlib.cmake 2020-07-22 18:16:07.200375473 +0200
|
||||
@@ -78,4 +78,4 @@
|
||||
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
||||
# TRUE if all listed variables are TRUE
|
||||
include (FindPackageHandleStandardArgs)
|
||||
-find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES hamlib_LIBRARY_DIRS)
|
||||
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
|
||||
diff -ur js8call-orig/CMakeLists.txt js8call/CMakeLists.txt
|
||||
--- js8call-orig/CMakeLists.txt 2020-07-22 18:14:18.014499840 +0200
|
||||
+++ js8call/CMakeLists.txt 2020-07-22 18:17:55.629633825 +0200
|
||||
@@ -558,7 +558,7 @@
|
||||
#
|
||||
# libhamlib setup
|
||||
#
|
||||
-set (hamlib_STATIC 1)
|
||||
+set (hamlib_STATIC 0)
|
||||
find_package (hamlib 3 REQUIRED)
|
||||
find_program (RIGCTL_EXE rigctl)
|
||||
find_program (RIGCTLD_EXE rigctld)
|
||||
@@ -911,56 +911,6 @@
|
||||
target_link_libraries (js8 wsjt_fort wsjt_cxx Qt5::Core)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
-# build the main application
|
||||
-add_executable (js8call MACOSX_BUNDLE
|
||||
- ${sqlite3_CSRCS}
|
||||
- ${wsjtx_CXXSRCS}
|
||||
- ${wsjtx_GENUISRCS}
|
||||
- wsjtx.rc
|
||||
- ${WSJTX_ICON_FILE}
|
||||
- ${wsjtx_RESOURCES_RCC}
|
||||
- images.qrc
|
||||
- )
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (js8call PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-set_target_properties (js8call PROPERTIES
|
||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
|
||||
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.kn4crd.js8call"
|
||||
- )
|
||||
-
|
||||
-target_include_directories (js8call PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
-if (APPLE)
|
||||
- target_link_libraries (js8call wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
-else ()
|
||||
- target_link_libraries (js8call wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
- if (OpenMP_C_FLAGS)
|
||||
- set_target_properties (js8call PROPERTIES
|
||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- LINK_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- )
|
||||
- endif ()
|
||||
- set_target_properties (js8call PROPERTIES
|
||||
- Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
- )
|
||||
- if (WIN32)
|
||||
- set_target_properties (js8call PROPERTIES
|
||||
- LINK_FLAGS -Wl,--stack,16777216
|
||||
- )
|
||||
- endif ()
|
||||
-endif ()
|
||||
-qt5_use_modules (js8call SerialPort) # not sure why the interface link library syntax above doesn't work
|
||||
-
|
||||
# if (UNIX)
|
||||
# if (NOT WSJT_SKIP_MANPAGES)
|
||||
# add_subdirectory (manpages)
|
||||
@@ -976,38 +926,10 @@
|
||||
#
|
||||
# installation
|
||||
#
|
||||
-install (TARGETS js8call
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION . COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (TARGETS js8 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTL_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctl-local${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLD_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctld-local${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (FILES
|
||||
- README
|
||||
- COPYING
|
||||
- INSTALL
|
||||
- INSTALL-WSJTX
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (FILES
|
||||
contrib/Ephemeris/JPLEPH
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
|
||||
@@ -1061,32 +983,6 @@
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/wsjtx_config.h"
|
||||
)
|
||||
|
||||
-
|
||||
-if (NOT WIN32 AND NOT APPLE)
|
||||
- # install a desktop file so js8call appears in the application start
|
||||
- # menu with an icon
|
||||
- install (
|
||||
- FILES js8call.desktop
|
||||
- DESTINATION /usr/share/applications
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
- install (
|
||||
- FILES icons/Unix/js8call_icon.png
|
||||
- DESTINATION /usr/share/pixmaps
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
- IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/js8call")
|
||||
- execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call)
|
||||
-
|
||||
- install(FILES
|
||||
- ${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
- endif()
|
||||
-endif (NOT WIN32 AND NOT APPLE)
|
||||
-
|
||||
-
|
||||
#
|
||||
# bundle fixup only done in Release or MinSizeRel configurations
|
||||
#
|
||||
Only in js8call/: .idea
|
@ -1,23 +0,0 @@
|
||||
diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh
|
||||
--- sdrplay-orig/install_lib.sh 2020-05-24 14:30:06.022483867 +0000
|
||||
+++ sdrplay/install_lib.sh 2020-05-24 14:30:49.093435726 +0000
|
||||
@@ -4,19 +4,6 @@
|
||||
export MAJVERS="3"
|
||||
|
||||
echo "Installing SDRplay RSP API library ${VERS}..."
|
||||
-read -p "Press RETURN to view the license agreement" ret
|
||||
-
|
||||
-more sdrplay_license.txt
|
||||
-
|
||||
-while true; do
|
||||
- echo "Press y and RETURN to accept the license agreement and continue with"
|
||||
- read -p "the installation, or press n and RETURN to exit the installer [y/n] " yn
|
||||
- case $yn in
|
||||
- [Yy]* ) break;;
|
||||
- [Nn]* ) exit;;
|
||||
- * ) echo "Please answer y or n";;
|
||||
- esac
|
||||
-done
|
||||
|
||||
export ARCH=`uname -m`
|
||||
|
@ -1,40 +0,0 @@
|
||||
diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh
|
||||
--- sdrplay-orig/install_lib.sh 2020-05-24 14:13:04.561271707 +0000
|
||||
+++ sdrplay/install_lib.sh 2020-05-24 14:16:20.068329040 +0000
|
||||
@@ -4,19 +4,6 @@
|
||||
MAJVERS="3"
|
||||
|
||||
echo "Installing SDRplay RSP API library ${VERS}..."
|
||||
-read -p "Press RETURN to view the license agreement" ret
|
||||
-
|
||||
-more sdrplay_license.txt
|
||||
-
|
||||
-while true; do
|
||||
- echo "Press y and RETURN to accept the license agreement and continue with"
|
||||
- read -p "the installation, or press n and RETURN to exit the installer [y/n] " yn
|
||||
- case $yn in
|
||||
- [Yy]* ) break;;
|
||||
- [Nn]* ) exit;;
|
||||
- * ) echo "Please answer y or n";;
|
||||
- esac
|
||||
-done
|
||||
|
||||
ARCH=`uname -m`
|
||||
|
||||
@@ -141,16 +128,6 @@
|
||||
echo "SDRplay API ${VERS} Installation Finished"
|
||||
echo " "
|
||||
|
||||
-while true; do
|
||||
- echo "Would you like to add SDRplay USB IDs to the local database for easier
|
||||
-"
|
||||
- read -p "identification in applications such as lsusb? [y/n] " yn
|
||||
- case $yn in
|
||||
- [Yy]* ) break;;
|
||||
- [Nn]* ) exit;;
|
||||
- * ) echo "Please answer y or n";;
|
||||
- esac
|
||||
-done
|
||||
sudo cp scripts/sdrplay_usbids.sh ${INSTALLBINDIR}/.
|
||||
sudo chmod 755 ${INSTALLBINDIR}/sdrplay_usbids.sh
|
||||
sudo cp scripts/sdrplay_ids.txt ${INSTALLBINDIR}/.
|
@ -1,39 +0,0 @@
|
||||
diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh
|
||||
--- sdrplay-orig/install_lib.sh 2020-05-24 13:56:56.622000041 +0000
|
||||
+++ sdrplay/install_lib.sh 2020-05-24 13:58:51.837801559 +0000
|
||||
@@ -4,19 +4,6 @@
|
||||
MAJVERS="3"
|
||||
|
||||
echo "Installing SDRplay RSP API library ${VERS}..."
|
||||
-read -p "Press RETURN to view the license agreement" ret
|
||||
-
|
||||
-more sdrplay_license.txt
|
||||
-
|
||||
-while true; do
|
||||
- echo "Press y and RETURN to accept the license agreement and continue with"
|
||||
- read -p "the installation, or press n and RETURN to exit the installer [y/n] " yn
|
||||
- case $yn in
|
||||
- [Yy]* ) break;;
|
||||
- [Nn]* ) exit;;
|
||||
- * ) echo "Please answer y or n";;
|
||||
- esac
|
||||
-done
|
||||
|
||||
ARCH=`uname -m`
|
||||
OSDIST="Unknown"
|
||||
@@ -157,15 +144,6 @@
|
||||
echo " "
|
||||
echo "SDRplay API ${VERS} Installation Finished"
|
||||
echo " "
|
||||
-while true; do
|
||||
- echo "Would you like to add SDRplay USB IDs to the local database for easier"
|
||||
- read -p "identification in applications such as lsusb? [y/n] " yn
|
||||
- case $yn in
|
||||
- [Yy]* ) break;;
|
||||
- [Nn]* ) exit;;
|
||||
- * ) echo "Please answer y or n";;
|
||||
- esac
|
||||
-done
|
||||
sudo cp scripts/sdrplay_usbids.sh ${INSTALLBINDIR}/.
|
||||
sudo chmod 755 ${INSTALLBINDIR}/sdrplay_usbids.sh
|
||||
sudo cp scripts/sdrplay_ids.txt ${INSTALLBINDIR}/.
|
@ -1,2 +0,0 @@
|
||||
#!/usr/bin/execlineb -P
|
||||
/usr/local/bin/sdrplay_apiService
|
@ -1,50 +0,0 @@
|
||||
--- CMakeLists.txt.orig 2021-03-30 15:28:36.956587995 +0200
|
||||
+++ CMakeLists.txt 2021-03-30 15:29:45.719326832 +0200
|
||||
@@ -106,24 +106,6 @@
|
||||
|
||||
|
||||
#
|
||||
-# build and install hamlib locally so it can be referenced by the
|
||||
-# WSJT-X build
|
||||
-#
|
||||
-ExternalProject_Add (hamlib
|
||||
- GIT_REPOSITORY ${hamlib_repo}
|
||||
- GIT_TAG ${hamlib_TAG}
|
||||
- GIT_SHALLOW False
|
||||
- URL ${CMAKE_CURRENT_SOURCE_DIR}/src/${__hamlib_upstream}.tar.gz
|
||||
- URL_HASH MD5=${hamlib_md5sum}
|
||||
- #UPDATE_COMMAND ${CMAKE_COMMAND} -E env "[ -f ./bootstrap ] && ./bootstrap"
|
||||
- PATCH_COMMAND ${PATCH_EXECUTABLE} -p1 -N < ${CMAKE_CURRENT_SOURCE_DIR}/hamlib.patch
|
||||
- CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --disable-shared --enable-static --without-cxx-binding ${EXTRA_FLAGS} # LIBUSB_LIBS=${USB_LIBRARY}
|
||||
- BUILD_COMMAND $(MAKE) all V=1 # $(MAKE) is ExternalProject_Add() magic to do recursive make
|
||||
- INSTALL_COMMAND $(MAKE) install-strip V=1 DESTDIR=""
|
||||
- STEP_TARGETS update install
|
||||
- )
|
||||
-
|
||||
-#
|
||||
# custom target to make a hamlib source tarball
|
||||
#
|
||||
add_custom_target (hamlib_sources
|
||||
@@ -161,7 +143,6 @@
|
||||
# build and optionally install WSJT-X using the hamlib package built
|
||||
# above
|
||||
#
|
||||
-ExternalProject_Get_Property (hamlib INSTALL_DIR)
|
||||
ExternalProject_Add (wsjtx
|
||||
GIT_REPOSITORY ${wsjtx_repo}
|
||||
GIT_TAG ${WSJTX_TAG}
|
||||
@@ -186,14 +167,8 @@
|
||||
DEPENDEES build
|
||||
)
|
||||
|
||||
-set_target_properties (hamlib PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
set_target_properties (wsjtx PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
|
||||
-add_dependencies (wsjtx-configure hamlib-install)
|
||||
-add_dependencies (wsjtx-build hamlib-install)
|
||||
-add_dependencies (wsjtx-install hamlib-install)
|
||||
-add_dependencies (wsjtx-package hamlib-install)
|
||||
-
|
||||
# export traditional targets
|
||||
add_custom_target (build ALL DEPENDS wsjtx-build)
|
||||
add_custom_target (install DEPENDS wsjtx-install)
|
@ -1,183 +0,0 @@
|
||||
diff -ur wsjtx-orig/CMake/Modules/Findhamlib.cmake wsjtx/CMake/Modules/Findhamlib.cmake
|
||||
--- wsjtx-orig/CMake/Modules/Findhamlib.cmake 2021-02-01 20:38:00.947536514 +0100
|
||||
+++ wsjtx/CMake/Modules/Findhamlib.cmake 2021-02-01 20:39:06.273680932 +0100
|
||||
@@ -85,4 +85,4 @@
|
||||
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
||||
# TRUE if all listed variables are TRUE
|
||||
include (FindPackageHandleStandardArgs)
|
||||
-find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES hamlib_LIBRARY_DIRS)
|
||||
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
|
||||
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
--- wsjtx-orig/CMakeLists.txt 2021-02-01 20:38:00.947536514 +0100
|
||||
+++ wsjtx/CMakeLists.txt 2021-02-01 23:02:22.503027275 +0100
|
||||
@@ -122,7 +122,7 @@
|
||||
option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
|
||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||
-option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
+option (WSJT_GENERATE_DOCS "Generate documentation files.")
|
||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
@@ -856,7 +856,7 @@
|
||||
#
|
||||
# libhamlib setup
|
||||
#
|
||||
-set (hamlib_STATIC 1)
|
||||
+set (hamlib_STATIC 0)
|
||||
find_package (hamlib 3 REQUIRED)
|
||||
find_program (RIGCTL_EXE rigctl)
|
||||
find_program (RIGCTLD_EXE rigctld)
|
||||
@@ -1376,60 +1376,6 @@
|
||||
target_link_libraries (jt9 wsjt_fort wsjt_cxx fort_qt)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
-# build the main application
|
||||
-generate_version_info (wsjtx_VERSION_RESOURCES
|
||||
- NAME wsjtx
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- )
|
||||
-
|
||||
-add_executable (wsjtx MACOSX_BUNDLE
|
||||
- ${wsjtx_CXXSRCS}
|
||||
- ${wsjtx_GENUISRCS}
|
||||
- ${WSJTX_ICON_FILE}
|
||||
- ${wsjtx_RESOURCES_RCC}
|
||||
- ${wsjtx_VERSION_RESOURCES}
|
||||
- )
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-set_target_properties (wsjtx PROPERTIES
|
||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
|
||||
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
- )
|
||||
-
|
||||
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
-if (APPLE)
|
||||
- target_link_libraries (wsjtx wsjt_fort)
|
||||
-else ()
|
||||
- target_link_libraries (wsjtx wsjt_fort_omp)
|
||||
- if (OpenMP_C_FLAGS)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- LINK_FLAGS "${OpenMP_C_FLAGS}"
|
||||
- )
|
||||
- endif ()
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
- )
|
||||
- if (WIN32)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||
- )
|
||||
- endif ()
|
||||
-endif ()
|
||||
-target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
-
|
||||
# make a library for WSJT-X UDP servers
|
||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
||||
@@ -1492,24 +1438,9 @@
|
||||
set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
endif (WSJT_CREATE_WINMAIN)
|
||||
|
||||
-if (UNIX)
|
||||
- if (NOT WSJT_SKIP_MANPAGES)
|
||||
- add_subdirectory (manpages)
|
||||
- add_dependencies (wsjtx manpages)
|
||||
- endif (NOT WSJT_SKIP_MANPAGES)
|
||||
- if (NOT APPLE)
|
||||
- add_subdirectory (debian)
|
||||
- add_dependencies (wsjtx debian)
|
||||
- endif (NOT APPLE)
|
||||
-endif (UNIX)
|
||||
-
|
||||
#
|
||||
# installation
|
||||
#
|
||||
-install (TARGETS wsjtx
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION . COMPONENT runtime
|
||||
- )
|
||||
|
||||
# install (TARGETS wsjtx_udp EXPORT udp
|
||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@@ -1528,12 +1459,7 @@
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
||||
# )
|
||||
|
||||
-install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
+install (TARGETS wsjtx_app_version jt9 wsprd
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@@ -1546,38 +1472,6 @@
|
||||
)
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTL_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctl-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLD_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctld-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (PROGRAMS
|
||||
- ${RIGCTLCOM_EXE}
|
||||
- DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
- #COMPONENT runtime
|
||||
- RENAME rigctlcom-wsjtx${CMAKE_EXECUTABLE_SUFFIX}
|
||||
- )
|
||||
-
|
||||
-install (FILES
|
||||
- README
|
||||
- COPYING
|
||||
- AUTHORS
|
||||
- THANKS
|
||||
- NEWS
|
||||
- BUGS
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (FILES
|
||||
cty.dat
|
||||
cty.dat_copyright.txt
|
||||
@@ -1586,13 +1480,6 @@
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
-install (DIRECTORY
|
||||
- example_log_configurations
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- FILES_MATCHING REGEX "^.*[^~]$"
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
#
|
||||
# Mac installer files
|
||||
#
|
@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
BUILD_PACKAGES="git cmake make gcc g++"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/jketterl/owrx_connector.git
|
||||
cmakebuild owrx_connector 0.4.0
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0"
|
||||
BUILD_PACKAGES="git libusb-1.0-0-dev cmake make gcc g++ pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/airspy/airspyone_host.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild airspyone_host 652fd7f1a8f85687641e0bd91f739694d7258ecc
|
||||
|
||||
git clone https://github.com/pothosware/SoapyAirspy.git
|
||||
cmakebuild SoapyAirspy 10d697b209e7f1acc8b2c8d24851d46170ef77e3
|
||||
|
||||
git clone https://github.com/airspy/airspyhf.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild airspyhf 8891387edddcd185e2949e9814e9ef35f46f0722
|
||||
|
||||
git clone https://github.com/pothosware/SoapyAirspyHF.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapyAirspyHF 5488dac5b44f1432ce67b40b915f7e61d3bd4853
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libhidapi-hidraw0 libhidapi-libusb0 libasound2"
|
||||
BUILD_PACKAGES="git cmake make gcc g++ libhidapi-dev libasound2-dev"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/pothosware/SoapyFCDPP.git
|
||||
cmakebuild SoapyFCDPP soapy-fcdpp-0.1.1
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0 libfftw3-3 udev"
|
||||
BUILD_PACKAGES="git cmake make patch wget sudo gcc g++ libusb-1.0-0-dev libfftw3-dev pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/mossmann/hackrf.git
|
||||
cd hackrf
|
||||
# latest from master as of 2020-09-04
|
||||
git checkout 6e5cbda2945c3bab0e6e1510eae418eda60c358e
|
||||
cmakebuild host
|
||||
cd ..
|
||||
rm -rf hackrf
|
||||
|
||||
git clone https://github.com/pothosware/SoapyHackRF.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapyHackRF 7d530872f96c1cbe0ed62617c32c48ce7e103e1d
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
BUILD_PACKAGES="git wget gcc libc6-dev"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $BUILD_PACKAGES
|
||||
|
||||
pushd /tmp
|
||||
|
||||
ARCH=$(uname -m)
|
||||
GOVERSION=1.15.5
|
||||
|
||||
case ${ARCH} in
|
||||
x86_64)
|
||||
PACKAGE=go${GOVERSION}.linux-amd64.tar.gz
|
||||
;;
|
||||
armv*)
|
||||
PACKAGE=go${GOVERSION}.linux-armv6l.tar.gz
|
||||
;;
|
||||
aarch64)
|
||||
PACKAGE=go${GOVERSION}.linux-arm64.tar.gz
|
||||
;;
|
||||
esac
|
||||
|
||||
wget https://golang.org/dl/${PACKAGE}
|
||||
tar xfz $PACKAGE
|
||||
|
||||
git clone https://github.com/jancona/hpsdrconnector.git
|
||||
pushd hpsdrconnector
|
||||
git checkout v0.4.2
|
||||
/tmp/go/bin/go build
|
||||
install -m 0755 hpsdrconnector /usr/local/bin
|
||||
|
||||
popd
|
||||
|
||||
rm -rf hpsdrconnector
|
||||
rm -rf go
|
||||
rm $PACKAGE
|
||||
|
||||
popd
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0 libatomic1"
|
||||
BUILD_PACKAGES="git libusb-1.0-0-dev cmake make gcc g++"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
SIMD_FLAGS=""
|
||||
if [[ 'x86_64' == `uname -m` ]] ; then
|
||||
SIMD_FLAGS="-DDEFAULT_SIMD_FLAGS=SSE3"
|
||||
fi
|
||||
|
||||
git clone https://github.com/myriadrf/LimeSuite.git
|
||||
cd LimeSuite
|
||||
# latest from master as of 2020-09-04
|
||||
git checkout 9526621f8b4c9e2a7f638b5ef50c45560dcad22a
|
||||
mkdir builddir
|
||||
cd builddir
|
||||
cmake .. -DENABLE_EXAMPLES=OFF -DENABLE_DESKTOP=OFF -DENABLE_LIME_UTIL=OFF -DENABLE_QUICKTEST=OFF -DENABLE_OCTAVE=OFF -DENABLE_GUI=OFF -DCMAKE_CXX_STANDARD_LIBRARIES="-latomic" ${SIMD_FLAGS}
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf LimeSuite
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0 libudev1"
|
||||
BUILD_PACKAGES="git make gcc autoconf automake libtool libusb-1.0-0-dev xxd"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/Microtelecom/libperseus-sdr.git
|
||||
cd libperseus-sdr
|
||||
# latest from master as of 2020-09-04
|
||||
git checkout c2c95daeaa08bf0daed0e8ada970ab17cc264e1b
|
||||
./bootstrap.sh
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
ldconfig /etc/ld.so.conf.d
|
||||
cd ..
|
||||
rm -rf libperseus-sdr
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. ${3:-}
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0 libxml2"
|
||||
BUILD_PACKAGES="git libusb-1.0-0-dev cmake make gcc g++ libxml2-dev flex bison pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/analogdevicesinc/libiio.git
|
||||
cmakebuild libiio v0.21 -DCMAKE_INSTALL_PREFIX=/usr/local
|
||||
|
||||
git clone https://github.com/analogdevicesinc/libad9361-iio.git
|
||||
cmakebuild libad9361-iio v0.2
|
||||
|
||||
git clone https://github.com/pothosware/SoapyPlutoSDR.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapyPlutoSDR 93717b32ef052e0dfa717aa2c1a4eb27af16111f
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0 libfftw3-3 udev"
|
||||
BUILD_PACKAGES="git cmake make patch wget sudo gcc g++ libusb-1.0-0-dev libfftw3-dev pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/pa3gsb/Radioberry-2.x
|
||||
cd Radioberry-2.x/SBC/rpi-4
|
||||
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapyRadioberrySDR 8d17de6b4dc076e628900a82f05c7cf0b16cbe24
|
||||
cd ../../..
|
||||
rm -rf Radioberry-2.x
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0-0"
|
||||
BUILD_PACKAGES="git libusb-1.0-0-dev cmake make gcc g++ pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/osmocom/rtl-sdr.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild rtl-sdr ed0317e6a58c098874ac58b769cf2e609c18d9a5
|
||||
|
||||
git clone https://github.com/pothosware/SoapyRTLSDR.git
|
||||
cmakebuild SoapyRTLSDR soapy-rtl-sdr-0.3.1
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0.0"
|
||||
BUILD_PACKAGES="git libusb-1.0.0-dev cmake make gcc g++ pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/osmocom/rtl-sdr.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild rtl-sdr ed0317e6a58c098874ac58b769cf2e609c18d9a5
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES=""
|
||||
BUILD_PACKAGES="git cmake make gcc g++ pkg-config"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/jketterl/runds_connector.git
|
||||
cmakebuild runds_connector 0.1.0
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,57 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0.0 udev"
|
||||
BUILD_PACKAGES="git cmake make patch wget sudo gcc g++ libusb-1.0-0-dev"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
ARCH=$(uname -m)
|
||||
|
||||
case $ARCH in
|
||||
x86_64)
|
||||
BINARY=SDRplay_RSP_API-Linux-3.07.1.run
|
||||
;;
|
||||
armv*)
|
||||
BINARY=SDRplay_RSP_API-ARM32-3.07.2.run
|
||||
;;
|
||||
aarch64)
|
||||
BINARY=SDRplay_RSP_API-ARM64-3.07.1.run
|
||||
;;
|
||||
esac
|
||||
|
||||
wget https://www.sdrplay.com/software/$BINARY
|
||||
sh $BINARY --noexec --target sdrplay
|
||||
patch --verbose -Np0 < /install-lib.$ARCH.patch
|
||||
|
||||
cd sdrplay
|
||||
./install_lib.sh
|
||||
cd ..
|
||||
rm -rf sdrplay
|
||||
rm $BINARY
|
||||
|
||||
git clone https://github.com/SDRplay/SoapySDRPlay.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapySDRPlay 105f8a6b3d449982d7ef860790c201aa066b8fa9
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="avahi-daemon libavahi-client3"
|
||||
BUILD_PACKAGES="git cmake make gcc g++ libavahi-client-dev"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/pothosware/SoapyRemote.git
|
||||
cmakebuild SoapyRemote soapy-remote-0.5.2
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libudev1"
|
||||
BUILD_PACKAGES="git cmake make patch wget sudo gcc g++"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/pothosware/SoapySDR
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapySDR 580b94f3dad46899f34ec0a060dbb4534e844e57
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,60 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libusb-1.0.0 libboost-chrono1.67.0 libboost-date-time1.67.0 libboost-filesystem1.67.0 libboost-program-options1.67.0 libboost-regex1.67.0 libboost-test1.67.0 libboost-serialization1.67.0 libboost-thread1.67.0 libboost-system1.67.0 python3-numpy python3-mako"
|
||||
BUILD_PACKAGES="git cmake make gcc g++ libusb-1.0-0-dev libboost-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-program-options-dev libboost-regex-dev libboost-test-dev libboost-serialization-dev libboost-thread-dev libboost-system-dev"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/EttusResearch/uhd.git
|
||||
# 3.15.0.0 Release
|
||||
mkdir -p uhd/host/build
|
||||
cd uhd/host/build
|
||||
git checkout v3.15.0.0
|
||||
# see https://github.com/EttusResearch/uhd/issues/350
|
||||
case `uname -m` in
|
||||
arm*)
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_UTILS=OFF -DENABLE_PYTHON_API=OFF -DENABLE_EXAMPLES=OFF -DENABLE_TESTS=OFF -DENABLE_OCTOCLOCK=OFF -DENABLE_MAN_PAGES=OFF -DSTRIP_BINARIES=ON \
|
||||
-DCMAKE_CXX_FLAGS:STRING="-march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 -Wno-psabi" \
|
||||
-DCMAKE_C_FLAGS:STRING="-march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 -Wno-psabi" \
|
||||
-DCMAKE_ASM_FLAGS:STRING="-march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 -g" ..
|
||||
;;
|
||||
aarch64*)
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_UTILS=OFF -DENABLE_PYTHON_API=OFF -DENABLE_EXAMPLES=OFF -DENABLE_TESTS=OFF -DENABLE_OCTOCLOCK=OFF -DENABLE_MAN_PAGES=OFF -DSTRIP_BINARIES=ON \
|
||||
-DCMAKE_CXX_FLAGS:STRING="-march=armv8-a -mtune=cortex-a72 -Wno-psabi" \
|
||||
-DCMAKE_C_FLAGS:STRING="-march=armv8-a -mtune=cortex-a72 -Wno-psabi" \
|
||||
-DCMAKE_ASM_FLAGS:STRING="-march=armv8-a -mtune=cortex-a72 -g" ..
|
||||
;;
|
||||
x86_64)
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_UTILS=OFF -DENABLE_PYTHON_API=OFF -DENABLE_EXAMPLES=OFF -DENABLE_TESTS=OFF -DENABLE_OCTOCLOCK=OFF -DENABLE_MAN_PAGES=OFF -DSTRIP_BINARIES=ON ..
|
||||
;;
|
||||
esac
|
||||
make
|
||||
make install
|
||||
cd ../../..
|
||||
rm -rf uhd
|
||||
|
||||
git clone https://github.com/pothosware/SoapyUHD.git
|
||||
cmakebuild SoapyUHD soapy-uhd-0.4.1
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,117 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ${CMAKE_ARGS:-} ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="sox libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline7 libgfortran4 libgomp1 libasound2 libudev1 ca-certificates libqt5gui5 libqt5sql5 libqt5printsupport5 libpulse0 libfaad2 libopus0 libboost-program-options1.67.0 libboost-log1.67.0"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-default libfaad-dev libopus-dev libgtest-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev"
|
||||
apt-get update
|
||||
apt-get -y install auto-apt-proxy
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
case `uname -m` in
|
||||
arm*)
|
||||
PLATFORM=armhf
|
||||
;;
|
||||
aarch64*)
|
||||
PLATFORM=aarch64
|
||||
;;
|
||||
x86_64*)
|
||||
PLATFORM=amd64
|
||||
;;
|
||||
esac
|
||||
|
||||
wget https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${PLATFORM}.tar.gz
|
||||
tar xzf s6-overlay-${PLATFORM}.tar.gz -C /
|
||||
rm s6-overlay-${PLATFORM}.tar.gz
|
||||
|
||||
JS8CALL_VERSION=2.2.0
|
||||
JS8CALL_DIR=js8call
|
||||
JS8CALL_TGZ=js8call-${JS8CALL_VERSION}.tgz
|
||||
wget http://files.js8call.com/${JS8CALL_VERSION}/${JS8CALL_TGZ}
|
||||
tar xfz ${JS8CALL_TGZ}
|
||||
# patch allows us to build against the packaged hamlib
|
||||
patch -Np1 -d ${JS8CALL_DIR} < /js8call-hamlib.patch
|
||||
rm /js8call-hamlib.patch
|
||||
CMAKE_ARGS="-D CMAKE_CXX_FLAGS=-DJS8_USE_HAMLIB_THREE" cmakebuild ${JS8CALL_DIR}
|
||||
rm ${JS8CALL_TGZ}
|
||||
|
||||
WSJT_DIR=wsjtx-2.3.1
|
||||
WSJT_TGZ=${WSJT_DIR}.tgz
|
||||
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
|
||||
tar xfz ${WSJT_TGZ}
|
||||
patch -Np0 -d ${WSJT_DIR} < /wsjtx-hamlib.patch
|
||||
mv /wsjtx.patch ${WSJT_DIR}
|
||||
cmakebuild ${WSJT_DIR}
|
||||
rm ${WSJT_TGZ}
|
||||
|
||||
git clone --depth 1 -b 1.6 https://github.com/wb2osz/direwolf.git
|
||||
cd direwolf
|
||||
# hamlib is present (necessary for the wsjt-x and js8call builds) and would be used, but there's no real need.
|
||||
# this patch prevents direwolf from linking to it, and it can be stripped at the end of the script.
|
||||
patch -Np1 < /direwolf-hamlib.patch
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf direwolf
|
||||
# strip lots of generic documentation that will never be read inside a docker container
|
||||
rm /usr/local/share/doc/direwolf/*.pdf
|
||||
# examples are pointless, too
|
||||
rm -rf /usr/local/share/doc/direwolf/examples/
|
||||
|
||||
git clone https://github.com/drowe67/codec2.git
|
||||
cd codec2
|
||||
# latest commit from master as of 2020-10-04
|
||||
git checkout 55d7bb8d1bddf881bdbfcb971a718b83e6344598
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
install -m 0755 src/freedv_rx /usr/local/bin
|
||||
cd ../..
|
||||
rm -rf codec2
|
||||
|
||||
wget https://downloads.sourceforge.net/project/drm/dream/2.1.1/dream-2.1.1-svn808.tar.gz
|
||||
tar xvfz dream-2.1.1-svn808.tar.gz
|
||||
pushd dream
|
||||
patch -Np0 < /dream.patch
|
||||
qmake CONFIG+=console
|
||||
make
|
||||
make install
|
||||
popd
|
||||
rm -rf dream
|
||||
rm dream-2.1.1-svn808.tar.gz
|
||||
|
||||
git clone https://github.com/mobilinkd/m17-cxx-demod.git
|
||||
# latest master as of 2021-04-20
|
||||
cmakebuild m17-cxx-demod c1d954fd5e5c53d28a2524e99484f832f9dcb826
|
||||
|
||||
git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols
|
||||
pushd /usr/share/aprs-symbols
|
||||
git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802
|
||||
# remove unused files (including git meta information)
|
||||
rm -rf .git aprs-symbols.ai aprs-sym-export.js
|
||||
popd
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ${CMAKE_ARGS:-} ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libfftw3-bin"
|
||||
BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++"
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/jketterl/js8py.git
|
||||
pushd js8py
|
||||
git checkout 0.1.0
|
||||
python3 setup.py install
|
||||
popd
|
||||
rm -rf js8py
|
||||
|
||||
git clone https://github.com/jketterl/csdr.git
|
||||
cd csdr
|
||||
git checkout 0.17.0
|
||||
autoreconf -i
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
cd ..
|
||||
rm -rf csdr
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p /etc/openwebrx/openwebrx.conf.d
|
||||
mkdir -p /var/lib/openwebrx
|
||||
mkdir -p /tmp/openwebrx/
|
||||
if [[ ! -f /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf ]] ; then
|
||||
cat << EOF > /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf
|
||||
[core]
|
||||
temporary_directory = /tmp/openwebrx
|
||||
EOF
|
||||
fi
|
||||
if [[ ! -f /etc/openwebrx/bands.json ]] ; then
|
||||
cp bands.json /etc/openwebrx/
|
||||
fi
|
||||
if [[ ! -f /etc/openwebrx/openwebrx.conf ]] ; then
|
||||
cp openwebrx.conf /etc/openwebrx/
|
||||
fi
|
||||
if [[ ! -z "${OPENWEBRX_ADMIN_USER:-}" ]] && [[ ! -z "${OPENWEBRX_ADMIN_PASSWORD:-}" ]] ; then
|
||||
if ! python3 openwebrx.py admin --silent hasuser "${OPENWEBRX_ADMIN_USER}" ; then
|
||||
OWRX_PASSWORD="${OPENWEBRX_ADMIN_PASSWORD}" python3 openwebrx.py admin --noninteractive adduser "${OPENWEBRX_ADMIN_USER}"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
_term() {
|
||||
echo "Caught signal!"
|
||||
kill -TERM "$child" 2>/dev/null
|
||||
}
|
||||
|
||||
trap _term SIGTERM SIGINT
|
||||
|
||||
python3 openwebrx.py $@ &
|
||||
|
||||
child=$!
|
||||
wait "$child"
|
||||
|
@ -1,162 +0,0 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
html, body {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #222;
|
||||
z-index: 2;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
|
||||
.row .map-input {
|
||||
margin: 15px 15px 0;
|
||||
}
|
||||
|
||||
.settings-section h3 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 1em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.matrix {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.q65-matrix {
|
||||
grid-template-columns: repeat(5, auto);
|
||||
}
|
||||
|
||||
.imageupload .image-container {
|
||||
max-width: 100%;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.imageupload img.webrx-top-photo {
|
||||
max-height: 350px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.settings-grid > div {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.settings-grid .btn {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
padding: 20px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.tab-body {
|
||||
overflow: auto;
|
||||
border: 1px solid #444;
|
||||
border-top: none;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.tab-body .form-group {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.bookmarks table .frequency, .bookmark-list table .frequency {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.bookmarks table input, .bookmarks table select {
|
||||
width: initial;
|
||||
text-align: inherit;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.bookmark-list table .form-check-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.actions .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wsjt-decoding-depths-table {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wsjt-decoding-depths-table td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sdr-device-list .list-group-item,
|
||||
.sdr-profile-list .list-group-item {
|
||||
background: initial;
|
||||
}
|
||||
|
||||
.sdr-device-list .sdr-profile-list {
|
||||
max-height: 20rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.removable-group.removable, .add-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.removable-group.removable .removable-item, .add-group .add-group-select {
|
||||
flex: 1 0 auto;
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.removable-group.removable .option-remove-button, .add-group .option-add-button {
|
||||
flex: 0 0 70px;
|
||||
}
|
||||
|
||||
.option-add-button, .option-remove-button {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs > * {
|
||||
flex: 0 0 auto;
|
||||
width: unset;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs > select {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.imageupload.is-invalid ~ .invalid-feedback {
|
||||
display: block;
|
||||
}
|
12
htdocs/css/bootstrap.min.css
vendored
@ -1,34 +0,0 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: 500px;
|
||||
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #575757;
|
||||
box-shadow: 0 0 20px #000;
|
||||
}
|
||||
|
||||
.login .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
height: 50px;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.openwebrx-map {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-block-start: 5px;
|
||||
margin-block-end: 5px;
|
||||
padding-inline-start: 25px;
|
||||
}
|
||||
|
||||
/* don't show the filter in it's initial position */
|
||||
.openwebrx-map-legend {
|
||||
display: none;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* show it as soon as google maps has moved it to its container */
|
||||
.openwebrx-map .openwebrx-map-legend {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.openwebrx-map-legend ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.openwebrx-map-legend ul li {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.openwebrx-map-legend ul li.disabled {
|
||||
opacity: .3;
|
||||
filter: grayscale(70%);
|
||||
}
|
||||
|
||||
.openwebrx-map-legend li.square .illustration {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.openwebrx-map-legend select {
|
||||
background-color: #FFF;
|
||||
border-color: #DDD;
|
||||
padding: 5px;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
html, body
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||
}
|
||||
|
||||
.sprite {
|
||||
background-image: url(../gfx/openwebrx-sprites.png);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openwebrx-button.highlighted .sprite {
|
||||
background-image: linear-gradient(rgba(255,127,0,0.5), rgba(255,127,0,0.5)), url(../gfx/openwebrx-sprites.png);
|
||||
background-blend-mode: overlay;
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||
only screen and (min-device-pixel-ratio: 2) {
|
||||
.sprite {
|
||||
background-image: url(../gfx/openwebrx-sprites-2x.png);
|
||||
background-size: 198px 77px;
|
||||
}
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
.webrx-top-container {
|
||||
position: relative;
|
||||
z-index:1000;
|
||||
background-color: #575757;
|
||||
|
||||
background-image: url(../gfx/openwebrx-top-photo.jpg);
|
||||
background-position-x: center;
|
||||
background-position-y: top;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.openwebrx-description-container {
|
||||
transition-property: height, opacity;
|
||||
transition-duration: 1s;
|
||||
transition-timing-function: ease-out;
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
/* originally, top-bar + description was 350px */
|
||||
max-height: 283px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.openwebrx-description-container.expanded {
|
||||
opacity: 1;
|
||||
height: 283px;
|
||||
}
|
||||
|
||||
.webrx-top-bar {
|
||||
height:67px;
|
||||
|
||||
background: rgba(128, 128, 128, 0.15);
|
||||
margin:0;
|
||||
padding:0;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.webrx-top-bar > * {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.webrx-top-container, .webrx-top-container * {
|
||||
line-height: initial;
|
||||
box-sizing: initial;
|
||||
}
|
||||
|
||||
.webrx-top-logo {
|
||||
padding: 12px;
|
||||
/* overwritten by media queries */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.webrx-rx-avatar {
|
||||
background-color: rgba(154, 154, 154, .5);
|
||||
margin: 7px;
|
||||
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.webrx-rx-texts {
|
||||
/* minimum layout width */
|
||||
width: 0;
|
||||
/* will be getting wider with flex */
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.webrx-rx-texts div, .webrx-rx-texts h1 {
|
||||
margin: 0 10px;
|
||||
padding: 3px;
|
||||
white-space:nowrap;
|
||||
overflow: hidden;
|
||||
color: #909090;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.webrx-rx-title {
|
||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.webrx-rx-desc {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.openwebrx-rx-details-arrow {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons .button {
|
||||
display: block;
|
||||
width: 55px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons .button[data-toggle-panel] {
|
||||
/* will be enabled by javascript if the panel is present in the DOM */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons .button img {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons .button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.openwebrx-main-buttons .button:active {
|
||||
background-color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
|
||||
.openwebrx-main-buttons {
|
||||
padding: 5px 15px;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin:0;
|
||||
color: white;
|
||||
text-shadow: 0px 0px 4px #000000;
|
||||
text-align: center;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.webrx-rx-photo-title {
|
||||
margin: 10px 15px;
|
||||
color: white;
|
||||
font-size: 16pt;
|
||||
text-shadow: 1px 1px 4px #444;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.webrx-rx-photo-desc {
|
||||
margin: 10px 15px;
|
||||
color: white;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px 0px 6px #444;
|
||||
opacity: 1;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.webrx-rx-photo-desc a {
|
||||
color: #5ca8ff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.openwebrx-photo-trigger {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Responsive stuff
|
||||
*/
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.webrx-rx-texts {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.webrx-top-logo {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Sprites (images)
|
||||
*/
|
||||
|
||||
.sprite-panel-status {
|
||||
background-position: 0 0;
|
||||
width: 44px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-log {
|
||||
background-position: -44px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-receiver {
|
||||
background-position: -82px 0;
|
||||
width: 40px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-map {
|
||||
background-position: -122px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-settings {
|
||||
background-position: -160px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.openwebrx-rx-details-arrow--down .sprite-rx-details-arrow {
|
||||
background-position: 0 -65px;
|
||||
width: 43px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.openwebrx-rx-details-arrow--up .sprite-rx-details-arrow {
|
||||
background-position: -43px -65px;
|
||||
width: 43px;
|
||||
height: 12px;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
<TITLE>OpenWebRX Feature report</TITLE>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico" />
|
||||
<link rel="stylesheet" href="static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="static/css/admin.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.0/showdown.min.js"></script>
|
||||
<script src="static/lib/jquery-3.2.1.min.js"></script>
|
||||
<script src="static/lib/Header.js"></script>
|
||||
<script src="static/features.js"></script>
|
||||
</HEAD><BODY>
|
||||
${header}
|
||||
<div class="container">
|
||||
${breadcrumb}
|
||||
<h1>OpenWebRX Feature Report</h1>
|
||||
<table class="features table">
|
||||
<tr>
|
||||
<th>Feature</th>
|
||||
<th>Requirement</th>
|
||||
<th>Description</th>
|
||||
<th>Available</th>
|
||||
</tr>
|
||||
</table>
|
||||
${breadcrumb}
|
||||
</div>
|
||||
</BODY></HTML>
|
@ -1,23 +0,0 @@
|
||||
$(function(){
|
||||
var converter = new showdown.Converter();
|
||||
$.ajax('api/features').done(function(data){
|
||||
var $table = $('table.features');
|
||||
$.each(data, function(name, details) {
|
||||
var requirements = $.map(details.requirements, function(r, name){
|
||||
return '<tr>' +
|
||||
'<td></td>' +
|
||||
'<td>' + name + '</td>' +
|
||||
'<td>' + converter.makeHtml(r.description) + '</td>' +
|
||||
'<td>' + (r.available ? 'YES' : 'NO') + '</td>' +
|
||||
'</tr>';
|
||||
});
|
||||
$table.append(
|
||||
'<tr>' +
|
||||
'<td colspan=3>' + name + '</td>' +
|
||||
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
||||
'</tr>' +
|
||||
requirements.join("")
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
BIN
htdocs/gfx/font-expletus-sans/ExpletusSans-Medium.ttf
Normal file
93
htdocs/gfx/font-expletus-sans/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright (c) 2011, Jasper de Waard (jasper@designtown.nl),
|
||||
with Reserved Font Name "Expletus Sans".
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.6444445mm"
|
||||
height="9.847393mm"
|
||||
viewBox="0 0 20 34.892337"
|
||||
id="svg3455"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Map Pin.svg">
|
||||
<defs
|
||||
id="defs3457" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="12.181359"
|
||||
inkscape:cx="8.4346812"
|
||||
inkscape:cy="14.715224"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="-4"
|
||||
inkscape:window-y="-4"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata3460">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-814.59595,-274.38623)">
|
||||
<g
|
||||
id="g3477"
|
||||
transform="matrix(1.1855854,0,0,1.1855854,-151.17715,-57.3976)">
|
||||
<path
|
||||
sodipodi:nodetypes="sscccccsscs"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4337-3"
|
||||
d="m 817.11249,282.97118 c -1.25816,1.34277 -2.04623,3.29881 -2.01563,5.13867 0.0639,3.84476 1.79693,5.3002 4.56836,10.59179 0.99832,2.32851 2.04027,4.79237 3.03125,8.87305 0.13772,0.60193 0.27203,1.16104 0.33416,1.20948 0.0621,0.0485 0.19644,-0.51262 0.33416,-1.11455 0.99098,-4.08068 2.03293,-6.54258 3.03125,-8.87109 2.77143,-5.29159 4.50444,-6.74704 4.56836,-10.5918 0.0306,-1.83986 -0.75942,-3.79785 -2.01758,-5.14062 -1.43724,-1.53389 -3.60504,-2.66908 -5.91619,-2.71655 -2.31115,-0.0475 -4.4809,1.08773 -5.91814,2.62162 z"
|
||||
style="display:inline;opacity:1;fill:#ff4646;fill-opacity:1;stroke:#d73534;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle
|
||||
r="3.0355"
|
||||
cy="288.25278"
|
||||
cx="823.03064"
|
||||
id="path3049"
|
||||
style="display:inline;opacity:1;fill:#590000;fill-opacity:1;stroke-width:0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.8 KiB |
BIN
htdocs/gfx/openwebrx-3d-spectrum.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
htdocs/gfx/openwebrx-avatar-background.png
Normal file
After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 970 B |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 8.1 KiB |
BIN
htdocs/gfx/openwebrx-ha5kfu-top-logo.png
Normal file
After Width: | Height: | Size: 2.0 KiB |