Compare commits

...

533 Commits

Author SHA1 Message Date
Denny Sheirer
0492f19a95 Merge pull request #1770 from DSheirer/1769-release-0.6.0
#1769 Release version 0.6.0
2023-12-16 06:48:10 -05:00
Dennis Sheirer
098b039154 #1769 Release version 0.6.0 2023-12-16 06:44:15 -05:00
Denny Sheirer
5c6e6059f8 Merge pull request #1754 from tadscottsmith/openmhz-broadcasting
Add OpenMHz Broadcasting Support
2023-12-16 06:14:14 -05:00
Denny Sheirer
72d45543df Merge pull request #1768 from szechyjs/master
Fix osx nightly architectures
2023-12-16 05:21:06 -05:00
Jared Szechy
e96fc46315 Fix osx nightly architectures
Resolves #1766
2023-12-15 13:59:35 -05:00
Denny Sheirer
f0cfbb80dd Merge pull request #1764 from DSheirer/1760-dmr-vendor-ids
#1760 Update DMR vendor enumeration.
2023-12-14 07:50:12 -05:00
Dennis Sheirer
a199f03a60 #1760 Updates DMR vendor enumeration. 2023-12-14 07:47:45 -05:00
Denny Sheirer
526c9609ef Merge pull request #1762 from DSheirer/1761-hytera-dmr-talker-alias-and-status
#1761 DMR Hytera Tier 3 UTF-16 Talker Alias & Traffic Channel Talker Status CSBK
2023-12-14 07:13:36 -05:00
Dennis Sheirer
ec9ceeefb3 #1761 DMR decoder supports Hytera Tier 3 UTF-16 Talker Alias & new Traffic Channel Talker Status CSBKO 47. Implements a tracking feature to detect when vendors are playing games using non-standard CSBK CRC mask values by tracking when a non-standard mask value is consistently detected and applying that mask when the initial CRC check fails. 2023-12-14 07:10:30 -05:00
Denny Sheirer
b6c6505824 Merge pull request #1759 from DSheirer/1758-l3h-talker-alias-gps
#1758 P25 Phase 2 L3Harris Talker Alias and GPS Report.
2023-12-10 09:52:48 -05:00
Dennis Sheirer
93c61c48f9 #1758 Adds P25 Phase 2 L3Harris talker alias and GPS report. 2023-12-10 09:45:49 -05:00
Denny Sheirer
9b89e80bb5 Merge pull request #1756 from DSheirer/1753-sdrplay-remove-unsupported-ifagc-modes
#1753 SDRPlay - Remove Deprecated AGC Modes
2023-12-01 03:43:16 -05:00
Dennis Sheirer
e0ecaa6e08 #1753 Changes tuner editors to use toggle button for IF AGC mode and updates enum lookup to always return either ENABLE or DISABLE. Deprecates 3x enum values as no longer supported. 2023-12-01 03:39:57 -05:00
Denny Sheirer
a7c89b5d1a Merge pull request #1755 from DSheirer/1746-dmr-simplex-repeater
#1746 DMR Decoder - Simplex Repeater and DCDM Calls
2023-12-01 03:02:13 -05:00
Dennis Sheirer
834846d339 #1746 DMR Decoder now supports simplex repeater and DMDC modes of operation. 2023-12-01 02:58:27 -05:00
tadscottsmith
45c8bb73fa Authorization features. 2023-11-29 14:40:45 -06:00
Denny Sheirer
d2580f8a99 Merge pull request #1751 from DSheirer/1188-fully-qualified-radio-identiifer-aliasing
#1188 APCO25 (ISSI) Fully Qualified Radio & Fully Qualified Talkgroup Aliasing
2023-11-29 02:34:43 -05:00
Dennis Sheirer
804c2e6359 #1188 Add support for P25 fully qualified radio and talkgroup identifiers to aliases and alias lists. Resolve issue with ESN alias lookups. 2023-11-28 04:32:11 -05:00
Denny Sheirer
3f2ec612d5 Merge pull request #1745 from DSheirer/1743-cpu-load-info-not-available
#1743 CPU Status Indicator & Show/Hide Status Panel & Now Playing Channel Detail Tabs
2023-11-18 03:29:39 -05:00
Dennis Sheirer
8bead998f5 #1743 Resolves CPU status indicator strobing and adds control to show/hide status panel and now playing channel details tabs. 2023-11-18 03:26:21 -05:00
tadscottsmith
2ecdaba183 Initial commit. (#4) 2023-11-15 17:23:09 -06:00
Denny Sheirer
82cb10a03d Merge pull request #1738 from hans109h/patch-1
Update JavaFxWindowManager.java for #1619
2023-11-15 05:01:16 -05:00
Denny Sheirer
8717ce38eb Merge pull request #1741 from DSheirer/1735-radio-ref-api-invalid-county-id-temp-site
#1735 Radio Reference API - Temporary Site With County ID 99999 - Unknown Location
2023-11-15 04:55:02 -05:00
sheirerd
5858a85a50 #1735 Adds support for county ID with sentinel value of 99999 to indicate county unknown for sites of a system. 2023-11-15 04:51:07 -05:00
hans109h
65d16da997 Update JavaFxWindowManager.java for #1619
Fixes #1619
2023-11-14 11:10:16 -06:00
Denny Sheirer
b1b5ae5fd2 Merge pull request #1734 from DSheirer/1733-management-factory-module-missing
#1733 Java Module Missing (java.management)
2023-11-14 06:07:11 -05:00
sheirerd
b5ec6d8877 #1733 Updates gradle build script to explicitly include the java.management module. 2023-11-14 06:04:36 -05:00
Denny Sheirer
8599aebed9 Merge pull request #1730 from CrimeIsDown/rdio-scanner-http-fix
Fix Rdio Scanner API call to comply with HTTP standards
2023-11-12 07:36:57 -05:00
Denny Sheirer
2b9e753033 Merge pull request #1732 from DSheirer/1731-application-status-bar
#1731 Application Status Bar (cpu/memory/disk space).
2023-11-12 07:21:43 -05:00
Dennis Sheirer
dba50744a9 #1731 Adds application status bar with progress indicators for CPU, memory and disk space (event logs / recordings) usage. Updates user preferences to include threshold settings in the directories editor for max size for event logs and recordings. 2023-11-12 07:19:10 -05:00
Eric Tendian
490569e023 Fix Rdio Scanner API call to comply with HTTP standards 2023-11-12 00:43:48 -06:00
Denny Sheirer
e79f2af759 Merge pull request #1728 from DSheirer/1619-javafx-windows-reappear-iconified
#1619 JavaFX Windows Restore to Previous Size/Location On View Request
2023-11-11 06:47:27 -05:00
Dennis Sheirer
ec7ee1ce91 #1619 JavaFX windows restore to previous size on view. 2023-11-11 06:45:23 -05:00
Denny Sheirer
672207c27c Merge pull request #1727 from DSheirer/1726-application-root-dir-on-startup
#1726 Don't Auto-Create App Root In User Home Directory Once Changed
2023-11-11 06:28:40 -05:00
Dennis Sheirer
a1a6b3e988 #1726 On startup, application no longer auto-creates SDRTrunk folder and system properties in user's home directory when user has changed the application root in the user preferences. 2023-11-11 06:17:04 -05:00
Denny Sheirer
2347135614 Merge pull request #1725 from DSheirer/1554-view-logs-file-explorer
#1554 App View Menu Cleanup & File Explorer Location
2023-11-11 05:33:13 -05:00
Dennis Sheirer
93438ddd97 #1554 Updates application view menu to show user-selected file locations. Enhances menu items with icons. Changes icon for playlist editor tab. 2023-11-11 05:28:36 -05:00
Eric Tendian
ae31c41643 #1635 Add a special county agency to show all county freqs without an agency (#1724)
#1635 Playlist Editor Add a special county agency to show all county freqs without an agency.
Merge pull request #1724
2023-11-11 04:39:17 -05:00
Denny Sheirer
16aed8741d Merge pull request #1721 from DSheirer/1720-version-0.6.0-beta-5
#1720 Updates version to 0.6.0 Beta 5
2023-11-10 05:43:31 -05:00
Dennis Sheirer
e878ca0c7f #1720 Updates version to 0.6.0 Beta 5 2023-11-10 05:42:41 -05:00
Denny Sheirer
ca61dd2543 Merge pull request #1719 from DSheirer/1619-java-fx-windows-open-minimized
#1619 JavaFX Windows Show Minimized
2023-11-10 05:34:09 -05:00
Dennis Sheirer
6187253589 #1619 Resolves issue where JavaFX window size and placement might show minimized after application is started and an initial JavaFX window is opened and then closed, where it impacted subsequent JavaFX window openings. Corrects issue where JavaFX stage monitors were not being registered correctly, so that they could be deregistered prior to application shutdown. 2023-11-10 05:31:05 -05:00
Denny Sheirer
b51c80742f Merge pull request #1717 from DSheirer/1681-audio-recordings-incorrect-system-and-site
#1681 Audio Recorder Mixing Up System and Site When Decoding Multiple Systems
2023-11-10 04:51:54 -05:00
Dennis Sheirer
15352b9216 #1681 Resolves issue where audio recordings have incorrect system and site labels in metadata. Adds synchronized to channel processing manager's start channel request method to ensure that each channel is configured and started sequentially to avoid chance that simultaneous traffic channel grants occurring across two separate systems get inter-mingled on configuration and startup. 2023-11-10 04:34:45 -05:00
Denny Sheirer
a848b21ae8 Merge pull request #1716 from DSheirer/1715-rtl-tuner-v3-v4-mixed-tuning-issue
#1715 RTL2832 Tuner Issue When Using V4 Dongle With Other R820T Tuners
2023-11-10 03:49:53 -05:00
Dennis Sheirer
279aca7287 #1715 Resolves issue of using both legacy and new V4 RTL2832 dongles at same time causes errant tuning behavior on the first tuner that gets initialized. Removed static qualifier from VCO reference value so that each tuner is allowed to initialize correctly. 2023-11-10 03:47:01 -05:00
Denny Sheirer
88879c956a Merge pull request #1714 from DSheirer/732-p25p2-missing-from-identifier-call-event
#732 P25 Phase 2 - FROM ID Updated For Call Event Logging
2023-11-09 04:51:01 -05:00
Dennis Sheirer
729b7e27a8 #732 Resolves P25P2 call events sometimes missing FROM radio ID even though the ID was decoded. 2023-11-09 04:48:42 -05:00
Denny Sheirer
feaed168ae Merge pull request #1713 from DSheirer/967-bulk-alias-editor-set-recordable
#967 Multi-Alias Editor Supports Changing Record Audio Status
2023-11-09 04:34:28 -05:00
Dennis Sheirer
50edb18db3 967 Updates bulk alias editor to support editing alias recordable status. 2023-11-09 04:30:25 -05:00
Denny Sheirer
7302e2806d Merge pull request #1712 from DSheirer/968-alias-editor-clear-overlap-state
#968 Playlist Alias Editor - Clear Overlap Error Warning Once Resolved
2023-11-09 04:15:17 -05:00
Dennis Sheirer
8845306b4a #968 Resolves issue with clearing alias ID overlap state when the user edits the alias to correct the overlap. 2023-11-09 04:12:46 -05:00
Denny Sheirer
09e19e1486 Merge pull request #1708 from tadscottsmith/rdio-scanner-filename
Explicitly send filename to Rdio-Scanner.
2023-11-07 04:12:14 -05:00
Denny Sheirer
0f5478925c Update README.md 2023-11-07 04:01:40 -05:00
Denny Sheirer
09dce0b0d1 Merge pull request #1710 from DSheirer/1709-nightly-build-timestamp-info
#1709 Nightly Release Build Timestamp Info
2023-11-07 03:32:42 -05:00
Dennis Sheirer
ad98b1cb5e #1709 Adds build timestamp info to nightly releases. 2023-11-07 03:31:31 -05:00
tadscottsmith
8effd97749 Explicitly send filename to Rdio-Scanner. 2023-11-06 10:54:41 -06:00
Denny Sheirer
9dbed72c32 Merge pull request #1707 from DSheirer/1706-nightly-release
#1706 Github Action For Nightly Releases
2023-11-06 05:06:19 -05:00
Dennis Sheirer
b4dd3692b8 #1706 Github action to create nightly application releases. 2023-11-06 05:05:40 -05:00
Denny Sheirer
030cbb856c Update README.md 2023-11-06 04:36:59 -05:00
Denny Sheirer
511101e9b7 Merge pull request #1705 from DSheirer/1704-harris-patch-group-formatting
#1704 Patch Group Formatting
2023-11-06 02:52:49 -05:00
Dennis Sheirer
60dd2b2df7 #1704 Updates patch group format for compatibility. 2023-11-06 02:50:46 -05:00
Denny Sheirer
218dc94e02 Merge pull request #1701 from DSheirer/1644-sdrplay-api-3-12
#1644 SDRPlay API Version 3.12 For Mac OSX
2023-11-05 07:22:04 -05:00
Dennis Sheirer
2440f578b1 #1644 Update SDRPlay API for version 3.12 compatability 2023-11-05 07:20:29 -05:00
Denny Sheirer
09c87237cb Merge pull request #1700 from DSheirer/1651-gradle-build-version-naming
#1651 Version 0.6.0 Beta 4 and Version Naming Conventions
2023-11-05 07:10:00 -05:00
Dennis Sheirer
3d974ddd91 #1651 Increment version to 0.6.0 Beta 4 and add version naming conventions comments. 2023-11-05 07:08:18 -05:00
Denny Sheirer
1489c970ba Merge pull request #1699 from DSheirer/1653-channel-edit-with-filtering
#1653 Playlist Channel Edits With Applied Filter Produces Error
2023-11-05 06:58:36 -05:00
Dennis Sheirer
9e0afca3d1 #1653 Playlist channel edits with applied filter doesn't produce error 2023-11-05 06:56:49 -05:00
Denny Sheirer
99eda4013e Merge pull request #1698 from DSheirer/1654-playlist-editor-channel-frequency-sort
#1654 Playlist Channel Editor Frequency Column Sort
2023-11-05 06:32:23 -05:00
Dennis Sheirer
a62f81f890 #1654 Playlist channel editor sorts by frequency numerically (vs lexicographically) 2023-11-05 06:29:23 -05:00
Denny Sheirer
66f0731731 Merge pull request #1697 from DSheirer/1665-refresh-broadcastify-streams
#1665 Refresh Broadcastify Streams In Playlist Editor
2023-11-05 06:00:48 -05:00
Dennis Sheirer
dc239801c6 #1665 Add option to refresh available streams from broadcastify in playlist editor's streaming tab. 2023-11-05 05:58:32 -05:00
Denny Sheirer
d4ba0988bc Merge pull request #1696 from DSheirer/1673-playlist-editor-broadcastify-system-id
#1673 Broadcastify Call Streaming Config Editor's default value of 0 …
2023-11-05 05:24:03 -05:00
Dennis Sheirer
ad0f953b2a #1673 Broadcastify Call Streaming Config Editor's default value of 0 causes field to be uneditable. 2023-11-05 05:20:15 -05:00
Denny Sheirer
e1bc9eabd6 Merge pull request #1695 from DSheirer/1694-sdrplay-rsp-tuner-memory-leaks
#1694 SDRPlay RSP Memory Leak & Audio Playback Delays
2023-11-05 04:26:48 -05:00
Dennis Sheirer
d3dc1a8667 #1694 Resolves memory leak in SDRPlay RSP tuner implementation. Sample stream and event callback functions were using a global arena for memory allocation where memory was not being de-allocated. Changed to on-demand arena creation and deterministic memory de-allocation. Also, when using a reduced sample rate from the RSP tuner, the dispatcher was not keeping up with the inbound sample buffer rate, resulting in a buildup of RSP native sample buffers over time and causing growing audio delays with broken/stilted audio during playback. 2023-11-05 04:24:19 -05:00
Denny Sheirer
bf278120de Merge pull request #1692 from DSheirer/DSheirer-patch-1
Update README.md
2023-11-04 07:41:29 -04:00
Denny Sheirer
2f52f6e009 Update README.md 2023-11-04 07:41:12 -04:00
Denny Sheirer
02363c3113 Merge pull request #1690 from DSheirer/1689-harris-patch-group-prefixes
#1689 Increment Build 0.6.0 Beta 3 and Remove TG/RA prefixes for Harris Patch Groups
2023-11-04 07:13:10 -04:00
Dennis Sheirer
cfaac0fcbc #1689 Increment Build 0.6.0 Beta 3 and Remove TG/RA prefixes for Harris patch groups. 2023-11-04 07:12:29 -04:00
Denny Sheirer
bee0405e00 Merge pull request #1688 from DSheirer/1687-rtl2832-fc0013
Support For RTL2832 With Embedded FC0013 Tuner
2023-11-04 06:54:55 -04:00
Dennis Sheirer
50bdf0ee81 #1687 Adds support for RTL2832 with embedded FC0013 tuner. 2023-11-04 06:52:37 -04:00
Denny Sheirer
a27ddbe0d0 Merge pull request #1679 from DSheirer/1643-r828d-v4-tuner
#1643 RTL2832/R828D aka RTL-SDR V4 Dongle & Bias-T Support
2023-10-22 08:40:33 -04:00
Dennis Sheirer
0d652b9153 #1643 Adds support for RTL2832 with embedded R828D tuner and RTL-SDR.com V4 dongles. Introduces Bias-T support for all RTL-2832 dongles. 2023-10-22 08:38:16 -04:00
Denny Sheirer
9468fd189b Merge pull request #1677 from DSheirer/1607-harris-p25-patch-groups
#1607 P25 P1/P2 L3Harris Patch Group Support
2023-10-21 07:00:41 -04:00
sheirerd
215737ad9b #1607 Add support for L3Harris dynamic regroup/patch messages and events. Includes parsing for L3Harris unknown opcodes 10, 42 and 43. 2023-10-21 06:58:11 -04:00
Denny Sheirer
123c25b142 Merge pull request #1672 from DSheirer/1650-fm-decoder-7_5-bandwidth
#1650 Adds 7.5 kHz channel bandwidth option for FM channels.
2023-10-15 09:22:48 -04:00
Dennis Sheirer
af56198f0e #1650 Adds 7.5 kHz channel bandwidth option for FM channels. 2023-10-15 09:21:38 -04:00
Denny Sheirer
3c73fdfd6e Merge pull request #1671 from DSheirer/1670-dmr-cap-plus-missing-call-audio
#1670 Missing Audio Segments - DMR Cap+
2023-10-15 08:56:48 -04:00
Dennis Sheirer
b391ebbb5f #1670 Resolves missing audio segments for some DMR Cap+ call events. 2023-10-15 08:55:35 -04:00
Denny Sheirer
bad5a1f9f0 Merge pull request #1669 from DSheirer/1668-message-viewer-p25-support
#1668 Message Recording Viewer - P25P1 Support
2023-10-15 07:17:06 -04:00
Dennis Sheirer
a7470b463f #1668 Updates message recording (.bits) viewer to support P25 Phase 1. 2023-10-15 07:14:53 -04:00
Denny Sheirer
d6c706cb35 Merge pull request #1667 from DSheirer/1666-p25-moto-unit-gps
#1666 P25 Motorola Unit GPS Parsing & Plot to Map
2023-10-14 08:16:48 -04:00
Dennis Sheirer
a0d6950c75 #1666 P25 Motorola unit self-reported GPS location parsing and plotting to map. 2023-10-14 08:15:35 -04:00
Denny Sheirer
2495200b36 Merge pull request #1663 from DSheirer/1648-dmr-lrrp-not-plotting-map
#1648 DMR Embedded GPS & LRRP Plotting
2023-10-05 03:32:08 -04:00
Dennis Sheirer
bfe7ae0b1b #1648 Resolves issue with plotting DMR embedded GPS and LRRP positions. 2023-10-05 03:31:17 -04:00
Denny Sheirer
4912abbf07 Merge pull request #1662 from DSheirer/1661-dmr-gps-location-parsing-error
#1661 DMR Talker GPS Lat/Long Values Incorrect
2023-10-05 03:21:24 -04:00
Dennis Sheirer
2f2998d02e #1661 Resolves issue with parsing of DMR embedded GPS latitude and longitude values. 2023-10-05 03:20:17 -04:00
Dennis Sheirer
c96349fa1c Updates version to 0.6.0 Beta 2 2023-08-31 07:14:58 -04:00
Denny Sheirer
f640576cc3 Merge pull request #1646 from DSheirer/1637-dmr-cap-plus-and-max-trunking
#1637 DMR Cap+/CapMax Channel Frequency Map / Trunking Issue
2023-08-31 07:10:21 -04:00
Dennis Sheirer
77d725a488 #1637 Resolves issue with DMR Cap+/CapMax trunking channel to frequency map. Updates the DMR channel map to use LCN instead of LSN and aligns standard DMR with Tier-III DMR for channel identification.
Warning: breaking change.  Users will need to either recreate their DMR channel to frequency maps or simply delete and reload the channel from Radio Reference to correct the channel to frequency map.

Updates the DMR Decoder State to better track and update DMR events versus creating a new event and causing lots of scrolling in the event window of the Now Playing tab.
2023-08-31 07:06:50 -04:00
Denny Sheirer
2c0305f928 Merge pull request #1642 from DSheirer/1641-hytera-rrs-packets
#1641 DMR Hytera RRS packet support.
2023-08-27 07:47:14 -04:00
Dennis Sheirer
21fd61d507 #1641 DMR Hytera RRS packet support. 2023-08-27 07:44:43 -04:00
Denny Sheirer
8fb56a5342 Merge pull request #1640 from DSheirer/1638-hytera-encryption-parameters
#1638 DMR Decoder - Encryption Parameters & Hytera RRS
2023-08-26 07:36:31 -04:00
Dennis Sheirer
5d7b73f876 #1638 Enhances DMR decoder to include additional encryption details from two major vendor implementations. Adds Hytera short data Radio Registration Service (RRS) processing. 2023-08-26 07:32:46 -04:00
Dennis Sheirer
85b2a38058 Version 0.6.0 Beta 1 2023-08-19 05:16:20 -04:00
Denny Sheirer
c78517ee75 Merge pull request #1631 from DSheirer/1630-flc-arc4-encryption-parameters
#1630 DMR FLC ARC4/EP Encryption Parameters
2023-08-18 07:08:30 -04:00
Dennis Sheirer
ae116d3dfe #1630 Updates ARC4 FLC encryption parameters message to detect and parse both Hytera & Motorola message formats. 2023-08-18 07:06:26 -04:00
Denny Sheirer
93252f9a40 Merge pull request #1629 from DSheirer/1628-libusb-device-list-error
#1628 LibUsb Error -99 During Device Discovery
2023-08-18 03:57:50 -04:00
Dennis Sheirer
3c03a4db2e #1628 Handle libusb get device list error condition and retry with increased logging during error code -99 to determine what causes this error condition, primarily on some Linux systems. 2023-08-18 03:55:42 -04:00
Denny Sheirer
d0fcd617aa Merge pull request #1627 from DSheirer/1626-dmr-call-events-missing-timeslot
#1626 Updates DMR call events to include timeslot and adds DMR encryption info when available.
2023-08-15 04:01:52 -04:00
Dennis Sheirer
6ca0decbd6 #1626 Updates DMR call events to include timeslot and adds DMR encryption information when available. 2023-08-15 04:01:27 -04:00
Denny Sheirer
ddd9ca933e Merge pull request #1624 from DSheirer/1623-unknown-opcode-message-filter
#1623 P25 Message Filter Set - Unknown Vendor Opcode
2023-08-14 04:04:30 -04:00
Dennis Sheirer
b2cc29569e #1623 resolves issue with handling of unknown P25 trunking opcode in message filter set. 2023-08-14 04:03:06 -04:00
Denny Sheirer
411735772b Merge pull request #1622 from DSheirer/dmr-cap-plus-identifier-updates
#1618 DMR Decoder Message Enhancements
2023-08-13 08:38:12 -04:00
sheirerd
2ffb2963af #1618 Update Cap+ radio & group parsing, process TXI & voice frame encryption parameters, and many other changes to the DMR message processing. 2023-08-13 08:30:23 -04:00
Denny Sheirer
227c88c8a2 Merge pull request #1614 from DSheirer/1612-dcs-alias-identifier
#1612 Enhance aliasing to support DCS tones
2023-07-24 04:34:46 -04:00
Dennis Sheirer
cbe9c79498 #1612 Enhance aliasing to support DCS tones 2023-07-24 04:30:16 -04:00
Denny Sheirer
1b8c100b43 Merge pull request #1611 from DSheirer/1605-tuner-editor-fails-to-display
#1605 Blank Tuner Editor Panel on Certain Linux Configurations
2023-07-22 06:00:38 -04:00
Dennis Sheirer
30c5fd64f2 #1605 Resolves issue where certain Linux users were unable to display the tuner editor panel due to an issue with the frequency control editor's usage of custom cursor. 2023-07-22 05:55:43 -04:00
Denny Sheirer
3a6b486340 Merge pull request #1610 from DSheirer/1604-event-panel-row-layout
#1604 Event Panel UI Layout Creates Excess Space On Resizing
2023-07-22 05:25:11 -04:00
Dennis Sheirer
ded7335dbf #1604 Resolves issue with event panel UI layout creating excess space between history management panel and events table. 2023-07-22 05:21:26 -04:00
Denny Sheirer
005a4f8119 Merge pull request #1608 from DSheirer/1603-duplicate-events
#1603 De-Duplicate Call Events
2023-07-22 05:06:11 -04:00
Dennis Sheirer
1ac49bfa7f #1603 Resolves issue with de-duplicating events to allow call duration values to display correctly and minimize the quantity of duplicate events. 2023-07-22 04:57:26 -04:00
Denny Sheirer
c302c4d121 Merge pull request #1601 from DSheirer/1368-decode-event-filtering-2
1368 Enhance Message & Event Filtering Options
2023-07-14 06:51:57 -04:00
Dennis Sheirer
b0a524cf62 #1368 Restructures Message and Event filter framework. 2023-07-14 06:50:07 -04:00
Christopher Varner
d246ffff30 Adds event type as a filtering option in the Events tab 2023-07-03 05:56:50 -04:00
Denny Sheirer
adfc8b2d6f #1586 Resolves issue in P25 message framer where after transmitting the current message the mDataUnitId is set to null and this causes an NPE when subsequent code is executed prior to shutdown of the channel. (#1593)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-07-03 05:11:20 -04:00
Denny Sheirer
ad2ab08466 #1588 Use JDK20 and Gradle 8.2. Updates SDRPlay API for compatibility with JDK20 Project Panama Foreign Memory/Function changes. (#1589)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-07-02 06:42:27 -04:00
Denny Sheirer
f3369410b2 #1590 Resolves issue with RSP tuners generating too many native buffers causing excessive memory consumption (#1591)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-07-02 06:23:00 -04:00
Denny Sheirer
bac38a5bd8 #1584 Updates DMR & P25 decoders to stop processing residual samples from the current buffer after a traffic channel shutdown has been signalled. (#1585)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-25 03:56:08 -04:00
Denny Sheirer
e5f5df74ad #1563 Updates RSP tuner to produce sample buffers with optimal power-of-2 length to enable downstream vectorized operations. (#1583)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-24 09:09:30 -04:00
Denny Sheirer
b3837f581a #1581 Updates Rdio Scanner configuration editor to automatically append the 'api/call-upload' path to the end of the protocol and host value provided by the user. Sets the host default value to 'http://localhost' but allows the user to overwrite. (#1582)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-24 07:05:44 -04:00
Denny Sheirer
b2ab6f58e9 #1579 Resolves issue with array index out of bounds error generated in P25 Phase 1 decoders where the Dibit circular buffer attempts to write a (#1580)
dibit past the length of the array.  Issue likely occurs when a partial/incomplete put operation adds a dibit and increments the buffer pointer but the thread is interrupted prior to wrapping the buffer pointer.  When the next runnable iteration executes, the pointer is pointing past the end of the buffer.  Updates the code to check the pointer both before and after the put operation.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-24 06:09:57 -04:00
Denny Sheirer
e04b59ba15 #1575 Updates traffic channel names to be 'T-' concatenated with the parent control channel name from the channel configuration. (#1578)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-24 05:15:27 -04:00
Denny Sheirer
366eacd234 #1573 Adds Digital Coded Squelch (DCS) auxiliary decoder support. (#1574)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-19 05:13:58 -04:00
Denny Sheirer
f792876c0a #1568 Updates NBFM decoder configuration so user can enable/disable high-pass filter option in the audio module to effect audio playback and audio recording of the demodulated audio. Disabling the filter allows recording of DC and sub-audible signalling that may be present in the demodulated audio (e.g. LTR or squelching signalling). (#1569)
Co-authored-by: sheirerd <sheirerd@ainfosec.com>
2023-06-05 07:19:16 -04:00
Denny Sheirer
19f7a5171b #1565 updates LTR, LTRNet and Passport decoders with new slope decoder. Resolves issue with LTR Standard decoder state that was combining individual calls to the same talkgroup and causing excessively long calls. (#1567)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-06-05 06:13:12 -04:00
Denny Sheirer
5b6377cc11 #1558 Resolves issue where heterodyne channelizer allows tuning a set of channels that exceed the tuner's bandwidth. (#1561)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-21 06:12:11 -04:00
Denny Sheirer
9502ca3069 #1547 Updates playlist alias editor to make add/delete operations more efficient. (#1560)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-21 04:54:26 -04:00
Denny Sheirer
77629000b2 #1548 Reduces default decoder AF gain by 40% to resolve issue with distorted audio from local strong aircraft transmissions. (#1559)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-21 04:16:51 -04:00
Nokoa
ca7916f992 added Rsp1TunerConfiguration to JsonSubTypes of RspTunerConfiguration (#1555)
Following reports that RSP1 tuner configurations are reset to default on startup. Unable to test
2023-05-20 07:45:05 -04:00
Denny Sheirer
9de83843a3 #1556 DMR Capacity Plus parsing enhancements. (#1557)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-20 07:44:07 -04:00
tadscottsmith
cbab7bb0c9 Adds native Rdio Scanner streaming. (#1) (#1476)
#1476 Adds rdio-scanner call upload API streaming support
---------

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-15 05:28:07 -04:00
wedgef5
3df8d60eed #1507 Resolves issue with Cap+ LSN parsing. Updates Cap+ Site Status and adds RAS bit handling. (#1536)
Co-authored-by: Matthew Foster <matthew.foster@noaa.gov>
2023-05-14 08:03:49 -04:00
Denny Sheirer
b39dd1a19f #648 Resolves issue with audio panel sometimes displaying stale metadata that doesn't clear until the next audio segment is loaded. (#1545)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-10 04:29:46 -04:00
Denny Sheirer
0af5963d08 #1528 Restores consistent audio segment start tone insertion, broken in #1506 (#1543)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-08 03:59:42 -04:00
Denny Sheirer
4f8b8e978b #35 Updates AM & NBFM decoders to use Adaptive Squelch, a power squelch that includes an adaptive noise floor monitor. Implements vectorized magnitude operations for AM & FM decoders. Adds talkgroup assignment and squelch controls to AM channel configuration editor. Implements new AM gain control that attempts to normalize audio gain quickly at beginning of call/transmission and maintains that gain across lifecycle of the call and resets the gain for the next call. (#1540)
Notes on usage:
- When using either AM or FM squelch control use either the Heterodyne channelizer or if using the Polyphase channelizer, avoid using trunk tracking decoders like DMR or P25 or set the squelch threshold high enough to avoid changes in noise floor from polyphase channelizer where it can vary between using the one channel or the two-channel combined channel sources.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-05-07 07:27:44 -04:00
Dennis Sheirer
5654254cbb Revert "#1531 Updates version to 0.6.0 alpha 7 (#1532)"
This reverts commit 11f37e896a.
2023-04-24 04:39:20 -04:00
Denny Sheirer
11f37e896a #1531 Updates version to 0.6.0 alpha 7 (#1532)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-24 04:38:27 -04:00
Denny Sheirer
e8f563deeb #1529 Adds logging suppression to Broadcaster to limit total logged error messages. (#1530)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-24 04:36:02 -04:00
Denny Sheirer
f877354a11 #1455 Add Airspy HF+/Discovery Tuner Support (#1524)
* #1455 Add support for airspy hf+/discovery tuners

* #1455 testing updates

---------

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-15 07:18:37 -04:00
Denny Sheirer
df3d3b5ddc #1519 Adds null checking to channel results array to detect null on tuner shutdown. (#1520)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-13 04:31:46 -04:00
Denny Sheirer
59e74d70b4 #1515 Updates version to 0.6.0 alpha 5 (#1516)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-12 03:14:54 -04:00
Denny Sheirer
8d6b7c3ac8 #1511 Resolves issue with SDRPlay library crashes application when linux service is in stopped state. (#1514)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-11 04:32:58 -04:00
Denny Sheirer
372d2ff870 #1506 Resolves multiple performance issues: tuner freezing after a period of run time, buffer overflows, degraded audio playback. (#1513)
-Reduces message and event histories per channel from 500 to 200.
-Resolves issue of tuner freezing due to cancelled USB transfer buffers not being resubmitted.
-Reworks the audio playback system to remove in-progress call preemption and remove thread locks which can cause glitchy behavior during audio playback.
-Updates audio outputs to also use single thread pool for processing audio segments.
-Updates MBECallSequenceConverter to batch convert MBE to WAV audio.
-Unifies recording filename prefixes across baseband, mbe and binary recordings.
-Resolves issue with registering heartbeat manager to dispatcher.
-Uses single-thread thread pools for Dispatcher to support batch & process to overcome context switching consistency issue in Windows.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-04-11 04:07:41 -04:00
Denny Sheirer
32a8363b45 Update issue templates
Updated issue templates.
2023-03-25 06:49:58 -04:00
Denny Sheirer
87f1f8986f Update issue templates
Adds issue template to prevent end-users from posting support questions in the issues/bug tracker.
2023-03-25 06:48:08 -04:00
Denny Sheirer
b3c08053fb Update issue templates
Adds feature request template.
2023-03-25 06:42:27 -04:00
Denny Sheirer
a5208dcf1e Update issue templates
Initial bug report template.
2023-03-25 06:40:11 -04:00
Denny Sheirer
2782953518 #1500 Makes Channel Auto-Start timeout a user-preference item to select in range 0-30 seconds. (#1501)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-21 04:32:28 -04:00
Denny Sheirer
366055145e #1498 Updates JMBE audio module to retain class reference instead of reflectively loading the class each time for a new instance. Reduces pressure on both the class loader and the garbage collector. (#1499)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-20 19:56:57 -04:00
Denny Sheirer
39ebdb47b1 #1491 Adds diagnostic logging to dispatcher to support troubleshooting polyphase channel manager's dispatch thread being blocked. (#1492)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-12 09:21:37 -04:00
Denny Sheirer
c788292db8 #1489 SDRPlay RSP tuner editors now lock sample rate combo when sourcing channels. (#1490)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-12 07:21:23 -04:00
Denny Sheirer
f0dc80437c #1487 Updates hot code classes to remove usage of reentrant locks for thread synchronization. (#1488)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-11 16:04:55 -05:00
Denny Sheirer
2d6c5c2331 #1485 Sets Blackman-Harris 7 As Default FFT Window (#1486)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-11 15:05:25 -05:00
Denny Sheirer
bc4e6cb5b0 #1473 Adds IF AGC Control for RSP tuners and Power Overload indication. Reverts changes to default MacOS library location in API. (#1484)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-11 14:58:58 -05:00
Denny Sheirer
d69ad46c10 #1471 Handling of unknown Hytera packet messages. (#1483)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-03-11 06:04:06 -05:00
Denny Sheirer
ba7b616f88 #1405 resolves issue with polyphase channel thread not shutting down correctly. Resolves issue with building distro releases using non-local JDKs. (#1477)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2023-03-05 05:55:01 -05:00
Denny Sheirer
8355b7e3b9 #1471 Adds support for Hytera Proprietary Long Data Service SMS messages. Resolves issue parsing Multi-Block CSBKs. (#1472)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-26 10:23:00 -05:00
Denny Sheirer
22ffb656be #1464 Reduces logging when SDRplay API is not installed on local machine. (#1465)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-20 12:10:17 -05:00
Denny Sheirer
de80d2a6c1 #1459 Updates gradle build to fix bug related to building releases for each OS (#1463)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-20 12:04:48 -05:00
Denny Sheirer
a320b4a24f #1461 Updates expected sdrplay library path for OSX (#1462)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-20 04:55:50 -05:00
Denny Sheirer
fc13777211 #1456 Resolves issue with shutdown when no sdrplay api is available. Version update to 0.6.0 alpha-2 (#1457)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-19 10:18:19 -05:00
Denny Sheirer
75347f9d0a #52 SDRPlay RSP tuner support. (#1453)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-19 08:21:54 -05:00
Denny Sheirer
9abf64c6ab #1449 Updates version to 0.5.1 final (#1451)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-19 07:17:10 -05:00
Denny Sheirer
1702103f5d #1449 Updates version to 0.5.1 beta-2 (#1450)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-19 07:10:44 -05:00
Denny Sheirer
8f68a989b9 #1444 Adds: (#1447)
* DMR Recording viewer utility
* DMR talker aliases
* DMR SMS messages
* DMR Hytera Tier-III compressed talkgroups support
* DMR UDT packet sequences
* DMR Hytera Aloha and other unknown CSBK and Link Control messages

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-18 08:36:55 -05:00
Denny Sheirer
b51a0102ef #1422 Resolves issue where MotoTRBO IP Site Connect and Capacity Plus voice group user message not decoding Radio & Talkgroup IDs correctly. Creates standalone application for viewing DMR messages from recordings. (#1442)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-02-11 15:32:41 -05:00
Denny Sheirer
e177c2c6b0 #1426 Adds JRE accessibility module to support assistive technologies. (#1427)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2023-01-21 07:21:00 -05:00
Denny Sheirer
3567fdf51d #1393 Updates DMR Talkgroup and Radio ID editors to use correct formatting. Patch submitted by @hockeyref2 (#1425)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2023-01-20 06:50:18 -05:00
Denny Sheirer
323097ba65 #1423 Updates Icecast/Broadcastify feed to attempt reconnect following a mountpoint in use error response. (#1424)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2023-01-20 05:39:38 -05:00
Denny Sheirer
33f2bab7ac #1419 Reduce logging from USBTunerController for (temporary) failed transfer buffer resubmits. (#1420)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-18 04:38:30 -05:00
Denny Sheirer
c063cfb201 #1416 Updates P25-P1 To Expose ICMP & Unknown Packet Events in Event History View (#1417)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-16 05:31:27 -05:00
Denny Sheirer
e99aa3d3b4 #1411 Updates version to 0.5.0 beta1 (#1412)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-15 06:36:22 -05:00
Denny Sheirer
ec162ff84c #1408 Updates USB tuners to enhance transfer buffer error handling and logging. When an error occurs while (re)submitting a transfer buffer to LibUsb to fill with sample data, the buffer is temporarily placed in an error queue. Upon successfully submitting the next transfer buffer, we attempt to resubmit a buffer from the error queue, so that we wait until the device can accept buffers before trying to resubmit. If all transfer buffers are exhausted because they are in the error queue, then the tuner gets shutdown with an error state ... there's really no way to recover at this point. (#1409)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-15 06:16:37 -05:00
Denny Sheirer
f0db2865f2 #1397 Resolves issue where decoding channels go IDLE after period of time. Isolated the cause to a multi-threading issue where the polyphase channel manager receives notification that the tuner center frequency has changed and sets a flag to update each of the channels. This happens concurrent with a previous tuner center frequency change where the flag gets set and the second thread is updating the output processors with the previous frequency change and then unsets the frequency change flag, completely missing the second/latest frequency change update and causing the channels to all tune-out their desired signals as the tuner center frequency changes and the output channels continue mixing to the previous frequency. (#1407)
Identified and resolved issue where a 2-stream polyphase synthesizer was being updated with an incorrectly designed synthesis filter which was causing massive droop on the second half of the reconstructed channel.  Oddly enough, this didn't seem to impact the P25 decoders, but it may have impacted other decoding.

Identified and resolved issue with concurrent modification of the modules list in the processing chain associated with recent addition of the channel FFT view in the channel power tab.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-15 04:12:42 -05:00
Denny Sheirer
f97b2150b9 #1397 Adds channel fft frequency overlay, cursor readout, pll tracking indicator, and channel bandwidth lines. (#1406)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-13 04:28:00 -05:00
Denny Sheirer
8ce8aaddf9 #1399 Resolves device ID parsing issue for Motorola ARS Device Registration. (#1400)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2023-01-06 04:17:57 -05:00
Denny Sheirer
e4a85a4ed7 #1386 Updates version to 0.5.0 (final) (#1387)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-25 07:11:25 -05:00
Denny Sheirer
f61a415b43 #1383 Updates tuner editor to resolve sequencing issue where a recently enabled tuner was having its enabled state set to true and then enabling the tuner, which caused the tuner editor to mis-configure the tuner editor panel. (#1385)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-25 07:03:28 -05:00
Denny Sheirer
29ed3b4553 #1287 Disables event panel filtering until the feature is fully implemented with #1368. The current partial implementation is preventing valid events from displaying for protocols like DMR and likely others. (#1384)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-25 06:45:50 -05:00
Denny Sheirer
a87309e792 #1378 Resolves potential error where tuner shutdown (because of USB I/O error) hangs and causes application to run out of memory. This patch doesn't resolve the original issue with the USB I/O error, but it does ensure that the tuner shutdown which is happening on the USB processing thread, can complete in a timely fashion so that the application doesn't (potentially) crash from out of memory. (#1382)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-24 09:10:17 -05:00
Denny Sheirer
ddb5b5ef87 #1380 Improves Icecast streaming error handling and preserves streaming error messages for broadcast state to display in streaming status panel. Resolves issue with streaming status panel not showing icons and stream type. (#1381)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-24 07:48:04 -05:00
Denny Sheirer
7a58bf85b6 #1312 Resolves issue with radio reference editor attempting to access county info for a site that has county ID set to 0 (ie no county specified). (#1379)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-24 04:45:21 -05:00
Doug Hoffman
8707eb2c88 Correctly identify padded MP3 frames (#1375) 2022-12-23 06:12:44 -05:00
Denny Sheirer
08499ac73f #1237 Ensure MP3 input sample rate is supported by LAME encoder settings. (#1376)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-23 06:06:10 -05:00
Dennis Sheirer
70170ff70f Revert "Disable resampling if requested sample rate not supported"
This reverts commit 7de28519a1.
2022-12-18 08:29:35 -05:00
Denny Sheirer
bad5589c0d #1369 Updates to Version 0.5.0 Beta 7 (#1370)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-18 07:17:23 -05:00
Doug Hoffman
7de28519a1 Disable resampling if requested sample rate not supported 2022-12-18 04:57:21 -05:00
Doug Hoffman
bbd907514e Handle streaming audio as frames (#1244) 2022-12-18 04:46:07 -05:00
Denny Sheirer
4a68cd9407 #1364 Enhancements to resolve issue with tuner shutdown hang on application shutdown. (#1365)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-18 04:29:55 -05:00
Denny Sheirer
dc327a2855 #1362 Updates heterodyne channelizer with alternate sorted set implementation to resolve issue when determining if the tuner can tune a requested channel. (#1363)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 09:28:29 -05:00
Denny Sheirer
9af593a785 #1360 Resolves issue with Polyphase channelizer and decoded message timestamps for P25 and other protocols. (#1361)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 08:50:29 -05:00
Denny Sheirer
24f4c22cdd #1358 Resolves issue where decoded AMBE (DMR & P25-2) tone identifiers are not sent to the alias action manager. (#1359)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 07:35:16 -05:00
Denny Sheirer
bc462b9652 #1351 Restores semi-accurate timestamps of sample buffers to ensure P25 & DMR decoded messages have accurate timestamps and MBE recording voice frames have accurate timestamps. (#1357)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 06:39:35 -05:00
Denny Sheirer
047dec6da1 #1355 Updates logging libraries to latest version and updates logging libraries to latest version. (#1356)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 04:06:44 -05:00
Denny Sheirer
bf935555bb #1353 Resolves issue where polyphase channelizer would mis-tune channels after a period of time resulting in idle decoding channels. (#1354)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-12-17 03:54:50 -05:00
Dennis Sheirer
efe36b0682 Updates README 2022-12-03 09:29:20 -05:00
Denny Sheirer
a18d4498aa #1346 Updates radio reference library to version 15.1.9 (#1347)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-25 09:11:10 -05:00
Denny Sheirer
803dc2531c #1318 Resolves issue where bitstream recorder no longer works. Solution submitted by @apankowski. (#1345)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-24 06:16:44 -05:00
Denny Sheirer
1b062bcd06 #1343 Resolves issue where user-initiated FFT size change causes waterfall panel pixel array to be updated/resized while a memory image source repaint has been requested and the parameters become incongruent, causing an array index out of bounds error. Pushes the pixel array update operation onto the swing thread to ensure only a single thread is modifying the pixel map for rendering. (#1344)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-24 04:23:48 -05:00
Denny Sheirer
a24c3736f4 #1340 Updates tuner and frequency controllers to apply locking to ensure multi-threaded access to freuqency control planes doesn't allow center tuned frequency to become indeterminant which can result in channels being mistuned and stop decoding. (#1341)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 07:55:30 -05:00
Denny Sheirer
ac61b681e6 #1338 Updates logger to include date in log entries. Removes info logger when creating channel log files. (#1339)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:54:05 -05:00
Denny Sheirer
0866bfd555 #1336 Resolves issue with color setting changes not inheriting the correct translucency which causes the channel overlays in the spectral display to be solid color instead of semi-transparent. (#1337)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:43:28 -05:00
Denny Sheirer
79fed701d9 #1337 Updates build to use JDK19 for distribution images and updates all 3rd-party libraries to latest. Note: build system continues to be compatible with JDK 17 and 18, but Gradle 7.6 to build distribution images. Gradle 7.6 is not released yet, but RC3 is available. (#1335)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:36:41 -05:00
Denny Sheirer
48a93990e8 #1291 Updates DC removal processing across tuner sample streams to run on a periodic timer to reduce overall processing requirements. Updates build version to 0.5.0 beta 5 (#1292)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-07-23 08:14:31 -04:00
Denny Sheirer
414ba25d61 #1284 Resolves issue with inherent DC bias (-0.5) in RTL2832 sample conversion code. (#1285)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-07-16 08:58:09 -04:00
Shahar
f67f90e8b0 moved RecordingTuner ChannelizerType set to after the recording tuner was started. This way the sample rate is not 0. (#1279) 2022-07-11 04:34:17 -04:00
Dennis Sheirer
5751c70212 Updates to release versio 0.5.0 2022-07-11 04:21:03 -04:00
Denny Sheirer
4e15c426a8 #1253 Updates USB tuner controller to handle LibUsb bug where on resubmitting a completed transfer LibUsb tells us that the transfer is already submitted. This is happening on some Window systems. (#1263)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-24 04:11:26 -04:00
Denny Sheirer
ceda189260 #1179 Resolves issue with JMBE Creator running on OSX. (#1262)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-24 03:57:33 -04:00
Denny Sheirer
fce0ae33e7 #1181 Updates libusb osx aarch64 driver library and gradle build. (#1261)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-23 04:06:42 -04:00
Denny Sheirer
fc5c6ef841 #1257 restores recording tuner feature. sdrtrunk now supports multiple recording tuners. Recordings are automatically loaded/restored on application start and each recording tuner has to be manually enabled for use. (#1258)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-22 08:24:42 -04:00
Denny Sheirer
d0033578d5 #1181 Adds logging for mac users to install libusb if sdrtrunk can't load library. (#1251)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-15 07:05:53 -04:00
Dennis Sheirer
670ec3a097 Adds debug logging to USB tuner controller. 2022-05-15 06:37:25 -04:00
Denny Sheirer
8bfb1d5470 #1243 Updates USB tuner error handling to prevent stack overflow when tuner error occurs while streaming. (#1247)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-09 07:16:35 -04:00
Denny Sheirer
46a916a945 #1245 Updates spectral display show tuner options to allow new display without changing disabled state of primary display. (#1246)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-08 05:01:52 -04:00
Denny Sheirer
459e77390a #1241 Adds user preference to enable/disable audio normalization prior to MP3 encoding/recording. (#1242)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-07 07:11:40 -04:00
Doug Hoffman
f4ab46b79d Prefer talkgroup ID over radio ID for Calls (#1227) 2022-05-07 06:51:27 -04:00
Denny Sheirer
3c58e98788 #1239 Resolves issue where a user can't view the spectrum of a tuner when the spectral display is disabled. Tuner editor button overrides the property setting so that the view completes correctly. (#1240)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-07 06:36:42 -04:00
Doug Hoffman
36de81248c Don't show tuner on spectral display while disabled (#1236) 2022-05-07 06:30:11 -04:00
Dennis Sheirer
925353d515 Bump Version 0.5.0 Beta 3, Gradle 7.4.2, Embedded JDK 18.0.1 2022-05-04 14:51:27 -04:00
Denny Sheirer
7c32897321 #1229 Resolves issue with correctly identifying the port number for USB tuners that is causing some tuners not to be recognized and also generating udev errors when sdrtrunk attempts to start an already started device because it was incorrectly identified. (#1230)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-03 04:03:18 -04:00
Doug Hoffman
cbeda19d27 Generate audio metadata with correct to/from (#1215)
#1215 Generate audio metadata with correct to/from, preferring patch group, then talkgroup then other, for TO talkgroups.
2022-05-01 06:06:31 -04:00
Doug Hoffman
8148ca48af Normalize audio before recording (#1213)
#1213 Normalize audio before recording
2022-05-01 05:57:32 -04:00
VolFFProCoder
adcb55ffbc Add filter button to messages (#1098)
Adds filtering to channel decoded events panel.
2022-04-30 05:44:57 -04:00
Andrzej Pańkowski
1152b13220 Merge pull request #1177
* Fixes message filtering that was not being initialized.  Fixes minor spotted code issues
2022-04-30 04:25:33 -04:00
Doug Hoffman
166383e1ed Make Broadcastify Calls scheduled test configurable (#1218)
* Broadcastify Calls periodic keep-alive to avoid showing offline status
2022-04-30 04:04:10 -04:00
Denny Sheirer
0d5d1b20e3 #1223 Resolves NPE when Airspy and HackRF tuners are re-enabled after startup. Slight tweaks to TunerManager to change when discovered USB device startup takes place to potentially address intermittent fail on start for some tuners that users are seeing. Resolves issue where a started device was not unreferenced in LibUsb on shutdown. (#1224)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-29 08:00:18 -04:00
Denny Sheirer
77ea43f61a #1221 resolves null pointer exception in tuner editor when attempting to restart an error tuner. (#1222)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-28 04:40:52 -04:00
Denny Sheirer
f988344222 #1219 resolves issues with NPE and restarting an error tuner. (#1220)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-26 04:02:36 -04:00
Doug Hoffman
60489e1fef (icecast) Add support for inline metadata (#1212) 2022-04-25 04:38:54 -04:00
Doug Hoffman
ac8aa17a80 Check in with Broadcastify Calls to stay online while otherwise idle (#1214) 2022-04-24 05:15:34 -04:00
Denny Sheirer
25a42126df #1210 Resolves issue of tuner instances can't be garbage collected due to retained references. Updates several of the tuner controller and tuner editor classes to add/invoke dispose() methods to clear retained instance references. (#1216)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-24 04:56:10 -04:00
Denny Sheirer
1b90e0b50c #1209 updates tuner manager to properly deref usb devices on discovery. Updates tuner editors to separate enable/disable from tuner error state. Updates settings manager to disable auto-fail when loading xml file when unknown tags are encountered so that users' existing configs don't fail on startup and erase their existing settings. (#1211)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-23 06:05:12 -04:00
Denny Sheirer
7f5ad7eb20 Update README.md 2022-04-19 07:03:19 -04:00
Denny Sheirer
0e6713b6e2 Update README.md 2022-04-19 07:02:32 -04:00
Denny Sheirer
96d3996bec #1190 Tuner management redesign. Updates all tuners with direct threaded support. Incorporates USB Hotplug support. Adds black/white listing of tuners. Updates all tuner editors to have a common look and feel. Changes location of tuner configuration file and changes format to JSON. (#1208)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-18 07:30:58 -04:00
Denny Sheirer
0fb148d31e #1194 Resolves issue with audio stream bit rate scheduling that was causing stream disconnects for data rate under flows. (#1195)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-26 05:48:08 -04:00
Denny Sheirer
cebca28b19 Patch from @ImagoTrigger to implement headless operation: 9e4d2adfa9..c597d1967b (#1191)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-25 04:19:38 -04:00
Denny Sheirer
af8cc0255e #1186 removes error logging that indicates that a channel cannot be stopped because it doesn't exist. This happens when a second successive attempt to stop a channel fails to find the channel because the first attempt has already removed the channel from the list. (#1187)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-03-21 19:09:49 -04:00
Dennis Sheirer
775ae00861 Update version to 0.5.0 beta 2 2022-03-21 05:48:16 -04:00
Denny Sheirer
1b80f5f1b3 #1178 removes synchronization on channel processing manager's source event handler to enable more fine-grained channel start/stop event processing. This was causing the channel start and stop events to occur sequentially. Adds stream processing with coordinated heartbeat. (#1185)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-21 05:47:20 -04:00
Dennis Sheirer
f9a7bbeddf Update version to 0.5.0 beta 1 2022-03-18 11:53:03 -04:00
Denny Sheirer
58a0264565 #1175 increases scheduled thread pool size from 2 to 4 threads. (#1176)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-18 11:45:24 -04:00
Denny Sheirer
6d2af95e9a #1173 updates DMR decoder to support DCDM (#1174)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-18 07:00:19 -04:00
Denny Sheirer
bf46b19dc9 #1169 Resolves issue where P25 C4FM decoder can request an interpolated sample value that is less than 0. Not sure why or what is causing this but this change guards against an ArrayIndexOutOfBounds exception when it does happen. (#1172)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-16 05:08:31 -04:00
Denny Sheirer
7749fd10f1 #1170 resolves issue with MP3 encoded audio raspy. Adds auto-clipping of PCM audio prior to encoding and adds 4x new 32-bit input sample rate selections to choose from, in addition to original 4x 16-bit input formats. (#1171)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-16 05:00:07 -04:00
Denny Sheirer
90bc321aca #1165 reverts changes to gradle runtimeZip task behavior. Enables 3 options for building target OS and CPU images: 1)build using local JDK, 2)build all targets using downloaded JDKs, or 3)download all JDKs and build all targets. (#1166)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-13 07:47:32 -04:00
Dennis Sheirer
bad4fae1b8 Updates README 2022-03-12 09:09:09 -05:00
Dennis Sheirer
c3fc435fdc Updates github action to use liberica jdk 17 plus fx libraries 2022-03-12 08:55:46 -05:00
JaredLThompson
2ab0c78728 Add error message for R828D Tuner (#1140) 2022-03-12 08:49:40 -05:00
hans109h
187989f6b8 Update README.md (#1158)
Corrects link to Bellsoft JDK download rather than duplicating the Azul link.
2022-03-12 08:48:09 -05:00
Steve Myers
3b83412bcb Update gradle.yml (#1143) 2022-03-12 08:46:25 -05:00
Denny Sheirer
968ea458da #1163 resolves issue with airspy unpacked calibrations hanging. Updates each test to check elapsed timer on a more granular scale on the theory that the SIMD vector implementation is horribly slow on some systems. (#1164)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-12 08:33:55 -05:00
Denny Sheirer
a9f4fbbdd4 #1160 OSX aarch64 (M1) libusb support and JDK auto-download for target OS images. (#1161)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-12 07:43:58 -05:00
Dennis Sheirer
6b3b45e9af Cleanup. 2022-03-12 03:39:16 -05:00
Denny Sheirer
2355dfce07 #939 Adds MP3 encoder preferences to the User Preferences dialog and provides user control over sample rate and MP3 encoder settings. MP3 preferences are global and affect both recording and streaming. (#1159)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-10 04:17:35 -05:00
Dennis Sheirer
0e8c9591e4 #1154 updates JMBE creator to work correctly with arm32 and aarch64 architectures. 2022-03-06 07:30:48 -05:00
Denny Sheirer
54e4771f36 #1154 updates JMBE creator to work correctly with arm32 and aarch64 architectures. (#1155)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-06 07:00:49 -05:00
Denny Sheirer
b2eb245feb #1152 Resolves issue where patch groups were not being properly formatted when uploading to broadcastify calls api. (#1153)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-05 05:56:16 -05:00
Denny Sheirer
e826314d06 #1150 resolves issue with inability to create HTTPS SSL connections. (#1151)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-05 03:32:07 -05:00
Denny Sheirer
0eec2e7ab8 Updates complex decimation filters to use either scalar or vector optimal implementation. (#1148)
Updates HackRF native byte buffers with automatic DC removal.
Creates new half-band channel source to replace the cic-based channel source in the heterodyne channelizer.  Resolves issue in RTL native buffer processing.  Creates a CACHED thread pool and reduces the number of threads for the SCHEDULED thread pool to 2.  Changes each of the channel source implementations to use a dedicated thread (Dispatcher class) instead of the scheduled thread pool, to reduce the amount of buffered/retained samples objects in memory. Lots of other small changes and tweaks.
Removes last of Reusable buffer code.  Updates DFTProcessor to use a single thread scheduled executor.  Updates Polyphase channelizer to use threads instead of an executor.  Removes a number of unused classes.
Commenting out window calibration.  Scalar is faster in both implementations.
Adds vector and scalar implementations for windows.  Repackages window and window type classes.
WIP adds vector implementations for Airspy non-interleaved buffer iterator and calibration plugins for both interleaved and non-interleaved buffer iterators.
WIP adds vector implementations for Airspy interleaved buffer iterator.
Work on developing scalar and vector implementations of airspy sample conversion and airspy native buffer processing.
Introduces new INativeBuffer framework where tuner raw samples are retained in their native (compressed) format until when they're needed and they are converted on-demand into smaller complex sample buffers to aid garbage collection.
Removes all usage of ReusableComplexBuffers and ReusableChannelREsultsBuffers.  Updates polyphase channelizer to be more efficient in output channel processing.
Updates ViterbiDecoder to change Map usage to array for memory efficiency.
Updates channel processors to used scalar implementation for gain and mixer, until the polyphase channel results can be fixed to be a multiple of the SIMD lane width.
Resolves final changes for the conversion from interleaved sample arrays to complexsamples buffers for distributing baseband samples to channels and processing chains.
Updates tuner channel sources and all decoders to receive new complex samples buffers, removing the previous reusable complex buffers as the default baseband samples buffer object.
Still to resolve is the ComplexMixer implementations.  Needs validation and a calibration implementation with an update to the complex mixer factory.
Updates the DMR decoder to use optimal (scalar vs vector) implementations of filter and AGC controls.
Updates the AM demodulator for separated I&Q float sample processing.
Code review and testing changes.
updates build script for runtime configuration.
Integrates calibration manager with main sdrtrunk application.  Updates NBFMDecoder to use new optimized FIR and Decimation filter options.
Updates real half-band decimation filters to select the optimal (scalar vs vector) implementation.
Adds calibration manager plugins.
Adds calibration manager and plugins to determine the optimal (scalar vs vector) implementation type to use for various classes of dsp components.
Adds vector squelching FM demodulator and cleans up the IIR filter and power squelch to use all floats.
Adds vector implementation of FM demodulator.  This introduces a new interface that accepts i/q samples as two separate float arrays, versus an interleaved array, which enables more efficient processing.  This new complex sample interface will be used across the codebase eventually.
Adds ComplexOscillator and a SIMD version VectorComplexOscillator.  Deprecates the LowPhaseNoiseOscillator because the ComplexOscillator is about 35% faster.  The vectorized version is about 43% faster when SIMD lane width is 8x.
Adds new vector complex filters and new real oscillators.  Note: the RealOscillator using straight Java math sin() function is 3x slower than the existing legacy implementation.  Will replace this with a complex oscillator that only uses the real part.
Updates ComplexFIRFilter to be 50% more efficient.
Adds 23 tap filter implementations.  Will not add 63-tap implementations because they are slower than the default vector implementation.
Adds 15-tap customized vector half band filters.
Adds initial custom complex vector half-band decimation filters for 11-tap and 15-tap decimation filters..
Adds vector complex half band filter implementations.  Note: performance of the generic 64-bit 2-lane filter is horrible and is not included.
Optimizes complex half-band filter to be 27% more efficient.
Implements vectorized real half-band filter implementations.
Implements a new FIR filter class that processes sample buffers instead of single sample at a time.
Refactored all of the calibratons to be time-duration based.  Testing on windows i7 gen 3 CPU showed that it took 1000x longer for one of the calibrations to run, versus my AMD 5800x.
Changed gradle jvm args so that the windows plaf export is always applied.
Updates gradle build script to ensure incubator module is included and to cleanup javafx library management for building runtime images.
Testing tweaks and changes.
Adds logging limiter to dispatcher for buffer overflows
Adds User Preferences editor for performing Vector/SIMD calibrations and new startup dialog prompting the user to perform calibrations.
Updates calibration manager and all calibration implementations to add warm-up and test phases and to reduce the overall time it takes to calibrate a system.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-04 08:45:05 -05:00
Denny Sheirer
5e9c239ea3 #1133 Resolves decimation rate too small issue for NBFM decoder. (#1134)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-01-10 04:26:57 -05:00
Denny Sheirer
1fd9b0fbcb Resolves #1130 - restores real time PPM measured frequency error broadcasts from DMR, P25P1 and P2 decoders. (#1131)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-01-02 09:01:32 -05:00
Denny Sheirer
8413343e76 Resolves 1122. Adds decimation to NBFMDecoder so that channel bandwidth is reduced to min sample rate needed. This reduces the impact on channel power measurement from adjacent channels. (#1129)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-01-02 08:35:19 -05:00
Denny Sheirer
2a0427c559 Adds support for power-of-2 decimation for both real and complex sample buffers. Creates new class to analyze the filter attenuation rates using a variety of filter lengths and window options to enable selecting the optimal combination of cascaded power-of-2 half band decimation filters. (#1127)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-12-31 10:20:15 -05:00
Denny Sheirer
5d9d232585 #1110 Updates DMR MBE frame recorder to correctly handle calls on separate timeslots and to fully capture identifiers associated with calls. (#1120)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-28 07:12:40 -05:00
Denny Sheirer
f0f0329f9b #1118 LRRP Latitude Hemisphere parsing. Updates parser to treat latitude value as a 1-bit hemisphere flag followed by a 31-bit integer. Previously, this field was parsed as a 32-bit two's complement field. (#1119)
There may be two separate formats that are used for LRRP position fields where one treats the value as a two's complement field and the other as a 1-bit hemisphere indicator followed by a 31-bit positive integer.  If so, we'll need to expose a user-selectable flag to toggle one format or the other.

For now, this change won't impact any Northern hemisphere users.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-28 06:14:54 -05:00
Denny Sheirer
2a45849e6d #1115 Adds more parsing updates for LRRP packets. (#1116)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-27 13:42:04 -05:00
Denny Sheirer
aa89079e28 #1113 Updates LRRP protocol to correctly identify geo-fence positions and to add support for packet type identification. Corrects issue with N/S and E/W hemisphere calculations. (#1114)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-25 05:58:42 -05:00
Dennis Sheirer
31b9ee5910 #1014 Adds AMBE voice frame recording support. 2021-11-21 04:57:39 -05:00
Denny Sheirer
6a54fe101c #1014 Adds AMBE voice frame recording support. (#1108)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-21 04:56:58 -05:00
Denny Sheirer
87b3d34024 #1106 Adds half-band filter create to filter factory (#1107)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-21 04:17:54 -05:00
Denny Sheirer
b8bbe9264a #1104 Resolves issue where all assembled DMR packet sequences are occurring only on timeslot 2 (#1105)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-20 06:04:49 -05:00
Dennis Sheirer
0c7dd192b0 Disabled failing tests until test can be updated to work across all platforms. 2021-11-18 04:30:43 -05:00
Denny Sheirer
8b487d79e4 Adds Comparable to identifiers that are used in TreeSets. (#1103)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-15 04:20:08 -05:00
Justin Bull
cb83a8e870 Properly format and safely escape to CSV in DecodeEventLogger (#1092)
* Add failing test for toCSV()

* Add missing " to timeslot value

* Add failing test for quotes and commas in details

* Separate comma and quote tests

* Escape toCSV cells using utility

* Use CSVFormatter instead of escape utils

Allows us to control exactly how we want to format a CSV-valid row.

* Never have a null cell

Instead of using a stream map, opting for an explicit handling so the logger can explode when an unexpected null shows up. Prevents the situation where things are mysteriously blank, forcing developers to handle known null scenarios.
2021-11-15 03:53:52 -05:00
Denny Sheirer
0bc11a07cf Update README.md 2021-11-14 07:59:26 -05:00
Dennis Sheirer
560cbad5d7 Code cleanup. 2021-11-14 07:57:14 -05:00
Noah Lynch
87e9bf8749 Don't sort Alias TableView while bulk changes are applied (#1039)
* Don't sort backing SortedList while AliasBulkEditor is applying changes.

SortedList takes too long to sort and can cause large slowdowns and UI
freezes while many changes to Aliases are applied at once via the
AliasBulkEditor.
2021-11-14 07:47:27 -05:00
Wojciech
770f58c668 Show geo locations from DMR on map (#1001)
Thank you!
2021-11-14 07:36:34 -05:00
Denny Sheirer
4b806ecfde #36 NBFM squelch control. Updates NBFM decoder to incorporate squelch control. Squelch is a configuration item and also available to adjust at runtime with new 'Channel' tab in Now Playing window. All decoders were updated to produce continuous channel power (dB) measurements that are displayed in the Channel tab's new Power Meter. (#1100)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-14 06:59:58 -05:00
Denny Sheirer
7303e06943 Resolves #1094. (#1097)
Updates gradle build system to address classes that are now hidden in Java 17 and no longer exported from the base modules.

Updated build system to specifically call out JavaFX OS-specific libraries and target these to each of the OS-specific build products.

Removes jcenter as a maven repo since it's now deprecated.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2021-11-06 09:47:27 -04:00
Denny Sheirer
846b249fb3 Update README.md 2021-11-06 09:05:23 -04:00
Denny Sheirer
67f23494e2 Update README.md 2021-11-02 04:39:31 -04:00
Denny Sheirer
d7efb627d7 Update README.md
Updated JMBE audio library instructions.
2021-11-02 04:38:42 -04:00
Denny Sheirer
08bc0b9963 Update README.md
Updated readme with Java 17 requirement
2021-11-02 04:30:49 -04:00
Dennis Sheirer
d1ed46860c Updates gradle wrapper to use version 7.2 and updates build script for 7.2 compatibility. 2021-10-30 10:00:19 -04:00
Dennis Sheirer
38f694d262 Updates gradle wrapper to use version 7.2 and updates build script for 7.2 compatibility. 2021-10-30 07:52:27 -04:00
Denny Sheirer
75ef3217ac #1021 Corrects previous implementation of dot-product filtering using Math.fma() (#1025)
Co-authored-by: Denny <denny@denny-desktop>
2020-12-29 03:50:24 -05:00
Denny Sheirer
2847dff64a #1021 Updates FIR filter to use the java Math.fma floating point multiply and accumulate instruction for more efficient processing. (#1022)
Co-authored-by: Denny <denny@denny-desktop>
2020-12-27 06:48:37 -05:00
Denny Sheirer
f0d9ef99ea Resolves multi-threading issue in buffer assembler where sample listener is nullified while buffer processing is still in process. (#1005)
Co-authored-by: Denny <denny@denny-desktop>
2020-12-01 04:06:03 -05:00
Robert Scullin
67702096d7 RR User Interface Improvements, including Premium notices (#992)
* RR UX Improvements, including Premium notices

* Fixing Error handling bug in LoginDialog
2020-11-02 03:40:30 -05:00
Denny
88f124af9d Updates build to 0.5.0 Alpha 6. 2020-10-26 04:27:20 -04:00
Denny Sheirer
d34460c4e3 #986 Resolves issue with HackRF tuner not loading correctly. (#987)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-26 04:26:29 -04:00
Denny Sheirer
f4f3db7436 #973 Adds concurrent locking to primary tuner controller methods. (#983)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-25 08:59:06 -04:00
Denny
3ebfa90ca1 Updates build to 0.5.0 Alpha 5 2020-10-25 07:51:13 -04:00
Denny Sheirer
733fdd0d7a #981 Sets channel short title as ignore for serialization. (#982)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-25 07:49:12 -04:00
Noah Lynch
09893605eb Only update ViewByIdentifierEditor's list when the editor is selected (#944)
* Add type parameters to TableColumns to fix compiler warnings

* Only update AliasViewByIdentifierEditor list when the editor is selected

This prevents the editor's list from being rebuilt in the background as
aliases are updated.  This caused a massive slowdown when editing many
aliases with the AliasBulkEditor.

Bulk editing 1000 aliases apply time reduced from over a minute to under
5 seconds.
2020-10-25 06:54:04 -04:00
Robert Scullin
57468ef932 Fixes #740 - Adds Encrypted state to the Status column for P25 Phase 1 (#975) 2020-10-25 06:46:02 -04:00
Robert Scullin
c6afb1c133 Fixes #815 - Change usable bandwidth percentage based on Airspy samplerate (#976) 2020-10-25 06:33:25 -04:00
Denny Sheirer
05c0b51fde #979 Updates DMR Tier III channel number issues and provides user option to ignore CRC checksums for DMR decoder with RAS-enabled systems. Adds support for Tier III traffic channel system parameters SLCO message. (#980)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-25 06:09:57 -04:00
Denny Sheirer
de8cfa24f9 #959 Updates DMR decode event tracking and Con+ channel grant management. (#978)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-25 04:51:36 -04:00
Denny Sheirer
fe714c69a7 #956 Resolves issue with null pointer in identifier collection on channel start. (#977)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-24 04:43:15 -04:00
Denny Sheirer
ac219cf2ba #969 Resolves issue where P25P2 NAC value is saved incorrectly by configuration editor. (#970)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-17 04:47:48 -04:00
Denny Sheirer
77b1102100 #942 Adds channel number to neighbor report logging. (#965)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-16 07:02:29 -04:00
Denny Sheirer
5117e6cbe8 #961 Resolves issue where invoking channel actions from Swing thread causes error on JavaFX GUI thread. Removes the Start/Disable/Delete commands from the Swing menu options and replaces with a single View/Edit call to the JavaFX channel editor. Although this reduces ease/functionality, it sidesteps code complications until the main GUI can be recreated in JavaFX. (#964)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-16 06:38:05 -04:00
Denny Sheirer
61c4e13c3e #954 Channel rotation delay default value too small for MPT1327 and P25 channels. (#963)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-16 06:04:17 -04:00
Denny Sheirer
f1190b7be3 #960 Adds handling to broadcastify streaming to not log an error when broadcastify tells us to skip an audio upload. This is not an error because another broadcaster has already uploaded the audio segment. (#962)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-16 05:19:50 -04:00
Denny Sheirer
49e7087b9b #952 Resolves issue with concurrent access to processing chain map. (#953)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-12 09:33:49 -04:00
Denny Sheirer
c397b5a601 #950 Resolves issue where message and event panels were aggregating across all selected now playing channels. (#951)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-12 09:26:59 -04:00
Denny Sheirer
c809dcc609 #948 Updates build to 0.5.0 Alpha 4 and updates gradle script to embed JDK15 as the Java runtime. (#949)
Co-authored-by: Denny <denny@denny-desktop>
2020-10-12 09:18:53 -04:00
Denny Sheirer
7eec82deee #6 DMR Decoder (#947)
* #6 DMR decoder feature - work in progress

* #6 DMR Decoder.

* #6 DMR Decoder.  Code review updates.

Co-authored-by: Zhenyu Mao <maozhenyu@foxmail.com>
Co-authored-by: Denny <denny@denny-desktop>
2020-10-12 04:57:59 -04:00
Denny Sheirer
b061db1189 #903 updates rrapi library to resolve radio reference web service deserialization issue. (#923)
Co-authored-by: Denny <denny@denny-desktop>
2020-09-04 04:46:08 -04:00
Denny Sheirer
8715dd2d6b #908 Add AMBE tone info to audio recording file names. (#921)
Co-authored-by: Denny <denny@denny-desktop>
2020-09-03 05:02:52 -04:00
Denny Sheirer
63b0aaaa7f Resolves #909 MPT1327 call events don't show talkgroup aliases. (#920)
Co-authored-by: Denny <denny@denny-desktop>
2020-09-03 04:21:28 -04:00
Denny Sheirer
d20dd1af8c Resolves #910 MPT-1327 talkgroup editor tooltip. (#919)
Co-authored-by: Denny <denny@denny-desktop>
2020-09-03 04:14:24 -04:00
Denny Sheirer
e1f32d3d0b Resolves #905. Adds try/catch block to duplicate call detection processing block to ensure that any error generated during duplicate call processing doesn't kill the processing thread and cause a queue-backup memory leak. (#918)
Co-authored-by: Denny <denny@denny-desktop>
2020-09-03 04:07:30 -04:00
Denny Sheirer
eaa3433034 #895 Cleanup and Testing of FCD Pro and Pro Plus tuners. (#896)
Co-authored-by: Denny <denny@denny-desktop>
2020-07-25 16:27:04 -04:00
Denny Sheirer
838016c89f #893 Updates UDP packet to construct a Cellocator packet payload when the source UDP port is 231 and any time the packet contains the correct start packet identifier. Updates the decode event type label. (#894)
Co-authored-by: Denny <denny@denny-desktop>
2020-07-25 09:01:44 -04:00
Denny
030a88f5a3 Updates build to 0.5.0 alpha 3 2020-07-25 08:28:27 -04:00
Denny Sheirer
de3ba5529a #890 Resolves issue where radio reference channel import only imports 1 of multiple listed control channels and adds improved detection for P25P2 simulcast sites to set the decoder type to LSM. (#892)
Co-authored-by: Denny <denny@denny-desktop>
2020-07-25 08:26:19 -04:00
Denny Sheirer
7962758e05 #866 Cellocator Packet Support (#875)
Resolves #866 Implements cellocator packet support.
2020-07-25 07:55:12 -04:00
Denny Sheirer
0f9d1c0792 #886 Resolves issue with audio recording when duplicate call detection is enabled. (#891)
Co-authored-by: Denny <denny@denny-desktop>
2020-07-25 07:24:12 -04:00
Noah Lynch
48be38a2d8 Wrap setAliases() in Platform.runLater() (#885)
Fixes issue #884 (see issue for more info).

AliasItemEditor.save() modifies objects that are observed by the
TableView's underlying SortedList.  Thus, the TableView's selection can
change by calling save(), which means the ListChangeListener can be
fired.

This is a problem for two reasons.
1. The alert dialogue that prompts the user to save a modified alias
will show when the user presses the "save" button, because saving
modifies the selected alias and causes the list to update.

2. setAliases() calls Alert.showAndWait().  From the JavaDoc:
"It must not be called during animation or layout processing."
This statement is likely there because it can cause issues like the one
here: TableView's layout processing (and the list updating) is paused
and the list is further modified (by calling save()).  Thus, when the
processing is resumed the list is in a different and unexpected state.

Calling setAliases() from Platform.runLater() will allow the SortedList,
TableView, and any other involved objects to finish processing changes
before more modifications are made.  Additionally, it allows save(),
when called by pressing the save button, to complete and set the
modifiedProperty to false, so setAliases() does not display an
additional save prompt.
2020-07-25 07:08:39 -04:00
Noah Lynch
207893e5a8 Move BinaryMessage isFull() check into try block to prevent NPE. (#881)
From issue 879:
When a BitSetFullException is caught and reset(0) is called, the
BinaryMessage is set to null.

This should resolve issue 879.
2020-07-25 06:59:13 -04:00
CurtisHx
e07d6fa854 Log build information on startup (#878) 2020-07-25 06:51:24 -04:00
Denny Sheirer
e26698d0d8 #839 Updates logging for tuner unavailable to allocate traffic channel frequencies. Logs the frequency once and then suppresses further logging. (#870)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-16 05:17:05 -04:00
Denny
a8837c8e2a Updates version to 0.5.0-alpha2 2020-06-13 09:35:11 -04:00
Denny Sheirer
7395f02fb8 #864 Updates radio reference service library to resolve issue where the library wasn't parsing the system information object correctly and was assuming a singular bandplan object versus an array of bandplans. (#865)
Updating the service library prompted some minor changes with the way that county info objects are handled for each site.

Co-authored-by: Denny <denny@denny-desktop>
2020-06-13 08:16:37 -04:00
Denny Sheirer
706ada2940 #862 Updates JavaFX libraries to use version 13.0.2 (#863)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-12 05:39:01 -04:00
Denny Sheirer
d957846ab0 #837 Sorted list ArrayIndexOutOfBoundsException during alias save. (#858)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-11 04:59:15 -04:00
Denny Sheirer
bbe90ca74b #856 Adds support for resetting alias color selection in the alias bulk editor. (#857)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-11 04:26:40 -04:00
Denny Sheirer
96611fa2c2 #854 Resolves issue with radio reference system view where site list is getting squeezed by height requirements in the site editor components. (#855)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-10 16:11:17 -04:00
Denny Sheirer
c94edf05ef #851 Resolves issue with residual alias list names after playlist change. (#852)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-10 05:48:45 -04:00
Denny Sheirer
74adb6f30c #849 Resolves issue with frequency table column not updating after saving new channel configuration. (#850)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-10 05:34:21 -04:00
Denny Sheirer
421abe5768 #724 Resolves issue with usb transfer buffer(s) memory leak. (#847)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-09 04:33:33 -04:00
Denny Sheirer
1d003c561e #845 File Not Found when setting initial directory on JMBE library select button. (#846)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-08 04:47:19 -04:00
Denny Sheirer
b22177ee17 #829 Integrates JMBE Creator with new user preferences editor for auto-downloading and compiling the JMBE library from within sdrtrunk. (#844)
Co-authored-by: Denny <denny@denny-desktop>
2020-06-07 08:04:57 -04:00
Denny Sheirer
a1e8c761ef #438 Adds feature for duplicate call audio detection and suppression for playback, recording and streaming. (#835)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-27 06:08:53 -04:00
Denny Sheirer
ad194d1bab #818 Resolves P25 duplicate traffic channel issue where duplicate traffic channels were being allocated for the same frequency. (#834)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-25 06:29:56 -04:00
Denny Sheirer
2bb5082943 #831 Resolves issue with playlist editor and channel map editor. (#832)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-24 08:11:39 -04:00
Denny Sheirer
2c3648f8c2 #817 Resolves issue with jittery audio playback and recording for MPT1327 channels. (#830)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-24 07:58:59 -04:00
Andrzej Pańkowski
3d816c3570 MPT1327: Fix decoding of calls to past talkgroups (#824)
* MPT1327: Fix decoding of calls to past talkgroups

* Fixed updating event in case of teardown. Other improvements.
2020-05-21 05:22:12 -04:00
Andrzej Pańkowski
e1194d26bd MPT1327: Fix for call timeout setting not being honored (#823)
* MPT1327: Fix for call timeout setting not being honored
2020-05-21 05:14:50 -04:00
Denny Sheirer
8167e9e9f2 #812 Alias Bulk Editor feature (#821)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-18 05:11:48 -04:00
Denny Sheirer
3b357c4d40 Update README.md 2020-05-15 04:39:14 -04:00
Denny Sheirer
89cb54676d Update README.md 2020-05-09 12:06:38 -04:00
Denny Sheirer
73c251ff4d #804 Tracks main application gui maximized state on shutdown and restores to maximized on restart. (#811)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-09 11:36:01 -04:00
Denny Sheirer
0d51b39604 #808 Improves broadcastify calls socket reset exception handling. (#810)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-09 11:20:33 -04:00
Denny
af0dbf1566 Removes Debug Logging. 2020-05-09 10:08:34 -04:00
Denny Sheirer
01146a5624 #797 and #801 Code Review and Cleanup. (#807)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-09 09:47:39 -04:00
Denny Sheirer
316cdb4068 #800 Resolves issue with rendering of icons in playlist alias editor and slow loading of icons in dropdown combobox. Adds error checking to the icon manager to notify user when there is an issue with loading a custom icon in the ADD method. (#803)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-07 05:51:21 -04:00
Denny Sheirer
91cae70fa1 #799 resolves npe in alias hasBroadcastChannels() method (#802)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-07 04:30:07 -04:00
Denny Sheirer
2723926f83 #778 Updates Icon Manager to JavaFX. Resolves issue with displaying custom icons in alias editor. (#796)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-06 04:08:05 -04:00
Denny Sheirer
2aff9ee817 #788 Adds monitoring for maximized state of FX windows. (#794)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-04 14:57:26 -04:00
Denny Sheirer
c87e6553dc #789 Resolves screen capture menu item takes up whole menubar. (#793)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-04 14:48:24 -04:00
Denny Sheirer
5d580544e7 #766 Resolves issue with playlist alias editor clone alias feature causing multiple copies of alias. Changed clone feature to only use a shallow copy (no ids or actions). Removed alias event framework from code since all change notifications can now be detected by the alias model's aliasList property. (#791)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-04 06:20:49 -04:00
Denny Sheirer
08ea0e0f18 #786 Updates Broadcastify Calls api for new test endpoint and editor changes. Updates Icecast and Shoutcast configurations to correctly show configuration validation status. (#787)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-03 07:23:21 -04:00
Denny Sheirer
c8b441dbd4 #782 Resolves NPE error in AudioOutput (#785)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-03 05:30:29 -04:00
Denny Sheirer
1aa22789e5 #783 Resolves issue with P25 Phase 2 channel grants (#784)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-03 05:25:23 -04:00
Denny Sheirer
cff5494db4 #775 Playlist Editor Cleanup (#779)
* #775 Adds frequency column to channel editor

* #775 Resolves issue with changing channel processing flag on FX event thread

* #775 Removes auto-detect channel settings for P25 Phase 2 configurations.

* #775 Playlist editor cleanup actions.  Changes style of segmented buttons.  Fix issue with channel set processing not on FX thread.  Removes P25P2 auto-detect settings feature.  Adds frequency column to channel editor.

Co-authored-by: Denny <denny@denny-desktop>
2020-05-02 09:53:44 -04:00
Denny Sheirer
9bd6507342 #770 Resolves issue with correct display of P25 uplink channel frequency values. (#774)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-02 07:27:45 -04:00
Denny Sheirer
379461e649 #757 Implements Broadcastify Calls API audio broadcaster and resolves audio streaming error introduced with #5 (#773)
Co-authored-by: Denny <denny@denny-desktop>
2020-05-02 06:29:45 -04:00
Denny Sheirer
cc52ae5bd7 #5 Playlist Editor With Radio Reference Support (#760)
* WIP - Adds support for aliasing P25 Phase 2 tones.Playlist editor - adds editor support for alias actions

* Playlist editor implementation and integration into application is complete. Adds JavaFX window monitoring to persist window size/location across application runs.

Co-authored-by: Denny <denny@denny-desktop>
2020-04-26 07:53:43 -04:00
robekl
39f6d6c831 Performance improvements (#746)
* Misc minor performance improvements

* Use more concise loop syntax

* Use more concise Collection sort syntax

* Use StringUtils pad methods

* Optimize some loops and double-map-lookups

* Optimize array instantiation

There are two styles to convert a collection to an array: either
using a pre-sized array (like c.toArray(new String[c.size()])) or
using an empty array (like c.toArray(new String[0]).

In older Java versions using pre-sized array was recommended,
as the reflection call which is necessary to create an array
of proper size was quite slow. However since late updates of
OpenJDK 6 this call was intrinsified, making the performance
of the empty array version the same and sometimes even better,
compared to the pre-sized version. Also passing pre-sized array
is dangerous for a concurrent or synchronized collection as
a data race is possible between the size and toArray call
which may result in extra nulls at the end of the array,
if the collection was concurrently shrunk during the operation.

* Cleanup string concatenation

* Use EnumMap where possible

* Use FastMath instead of Math

* Initialize complex things only once

* Reduce method size to aloow more JIT inlining

* remove map of short->float

* Move field to local variable

* Cleanup Map lookup

Co-authored-by: Rob Ekl <xwq876@zebra.com>
2020-04-25 07:57:56 -04:00
robekl
649258bd2b Fix some minor bugs (#745)
* Include other member variables in copy constructor

* Add break to switch cases

* Implement equals() in classes extending Comparable

If equals() is not overridden, the equals() implementation is not consistent
with the compareTo() implementation. If an object of such a class is added
to a collection such as java.util.SortedSet, this collection will violate
the contract of java.util.Set, which is defined in terms of equals().

Co-authored-by: Rob Ekl <xwq876@zebra.com>
2020-04-25 05:52:14 -04:00
Denny Sheirer
de9431f649 Resolves #751 adds quoted, comma-separated aliases to TRACK_TITLE metadata tag. (#759)
Co-authored-by: Denny <denny@denny-desktop>
2020-04-25 05:46:31 -04:00
Denny Sheirer
18f9e38090 Updates HackRF Sample Rates (#744)
* Hackrf Changes

* Updates HackRF tuner controller sample rates to deprecate previous sample rates to ensure playlist settings don't get corrupted.

Co-authored-by: Doug <dswelch51964@yahoo.com>
Co-authored-by: Denny <denny@denny-desktop>
2020-04-19 10:57:05 -04:00
Denny Sheirer
2e37f1e687 Updates gradle wrapper to 6.3. Updates embeded java to JDK 14 for building platform releases. (#729)
Co-authored-by: Denny <denny@denny-desktop>
2020-04-04 09:22:13 -04:00
Denny Sheirer
5e8f2d0523 Updates build to 0.4.0 final and updates CHANGELOG revision history. (#727)
Co-authored-by: Denny <denny@denny-desktop>
2020-04-04 08:19:29 -04:00
crsawyer
9fb6c33319 Fix HackRF-JawBreaker and HackRF sample conversion (#725) 2020-04-04 08:02:17 -04:00
Denny Sheirer
fdecac4230 Resovles #721 Suppress RID values of 0. (#723)
Co-authored-by: Denny <denny@denny-desktop>
2020-04-01 05:05:28 -04:00
Denny Sheirer
85c27a6cca Resolves #719 P25 Phase 2 display channel number (#722)
Co-authored-by: Denny <denny@denny-desktop>
2020-04-01 03:28:26 -04:00
Denny Sheirer
57f56d31a2 #713 Update Version 0.4.0 Beta 8 (#714)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 12:06:23 -04:00
Denny Sheirer
df25675d3f Resolves #707 separate DTMF tones of the same value get merged together (#712)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 12:03:47 -04:00
Denny Sheirer
277a84702a Resolves #580 channel map selection and editing (#711)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 11:52:39 -04:00
Denny Sheirer
c651296378 Resolves #709 MPT1327 no audio on traffic channels. (#710)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 11:33:15 -04:00
Denny Sheirer
866d25e86a #705 Updates release version 0.4.0 beta 7 (#706)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 06:17:06 -04:00
Denny Sheirer
5e62f1b889 Resolves #677 Streaming Audio Metadata UNKNOWN/UNKNOWN (#704)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 05:58:21 -04:00
Denny Sheirer
e9d524ad14 Resolves #699 Channel Multi-Frequency rotation delay user preference does not persist. (#703)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-28 05:53:58 -04:00
Denny Sheirer
158c8b4b8a #701 P25 Phase 2 Tone Metadata and Channel State (#702)
* Resolves #701 Updates P25P2 Tone metadata handling and P25P2 channel state management.
2020-03-28 05:51:11 -04:00
Denny Sheirer
41df207bb9 Resolves #694. Address null pointer when no system audio devices are available. (#695)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-23 04:45:06 -04:00
Denny Sheirer
692ffabe82 Resolves #692. Updates Java requirement to version 13 and JavaFX libraries to version 13. (#693)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-22 09:30:43 -04:00
Denny
944ad5a571 Updates version to 0.4.0 beta 6 2020-03-22 06:39:53 -04:00
Denny
5ca70d3940 Removes logging from invalid channel type values. 2020-03-22 06:07:36 -04:00
Denny Sheirer
904752e3dd Resolves #688. Updates HackRF Sample Rate options and sets usable bandwidth for the tuner to 75% of the sample rate. (#689)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-22 05:31:56 -04:00
Denny Sheirer
cf61798466 Resolves #685. Resolves several issues with P25 Phase 2 channel state and call handling. (#687)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-21 14:42:04 -04:00
Denny Sheirer
fd72f459f9 Resolves #685. Resolves several issues with P25 Phase 2 channel state and call handling. (#686)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-21 14:31:26 -04:00
Denny Sheirer
1bc462b300 Resolves #676 Do Not Monitor feature not working. (#684)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-21 05:32:12 -04:00
Denny Sheirer
1c6f91f101 Resolves #682 NPE when logging channel events with no alias list specified. (#683)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-20 11:15:53 -04:00
Denny
a7c28f066a Resolved NPE with tone updates. 2020-03-20 09:14:10 -04:00
Denny Sheirer
604c8ab6e5 Resolves #680 Audio Do Not Monitor is not working. Adds audio segment drop tone to indicate that an audio playback is dropped because the do not monitor setting was applied after the audio segment started. (#681)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-20 08:31:35 -04:00
Denny Sheirer
23a3ee39cc Resolves #678 AudioChannelPanel threading issue. (#679)
Co-authored-by: Denny <denny@denny-desktop>
2020-03-20 05:21:49 -04:00
Denny Sheirer
fa16db129b #660 Updates audio processing subsystem to use audio segments. Updates audio playback, recording and streaming to use audio segments. Adds support to UserPreferences for sound card selection and audio tone insertion during playback. Adds record preference for WAVE or MP3. Resolves issues with metadata in recordings. (#675) 2020-03-19 06:35:05 -04:00
Denny
de249c448b Removes debug logging. 2020-02-29 11:02:32 +00:00
Denny
e1bc56c500 Resolves issue with build script where OS-specific JavaFX libraries were not included in build images. 2020-02-23 08:35:49 -05:00
Denny Sheirer
d1d115d11f Updates build to version 0.4.0 beta 5 (#668) 2020-02-23 09:49:00 +00:00
Allegiance Zone pusher
aca41b4f6e alias in event log.diff (#659) 2020-02-22 20:38:37 +00:00
whelgeson
1e3ae996ac Implementing some build script cleanup work. (#664)
- Adding jitpack to import libs directly from the git repos
 - Removing binary imports from repo
 - Fixing Gradle 7 upgrade warnings
2020-02-22 20:31:29 +00:00
Denny Sheirer
b3b2e74688 Resolves #663. Updates P25 phase 2 Decoder to detect PLL lock errors for +/-90 and 180 out-of-phase. Adds support for broadcasting phase 2 channel frequency error calculations to support tuner auto-correction for frequency errors. Removes adaptive PLL bandwidth support from Phase 1 and uses a fixed PLL bandwidth for both phase 1 and phase 2 decoders. Updates the Phase 2 symbol timing gain with results from extensive testing of PLL bandwidth and symbol timing combinations. (#666) 2020-02-22 20:09:24 +00:00
Denny Sheirer
44237bec5c Resolves issue where user added icons were not displaying on windows OS. (#658) 2020-02-16 12:22:27 +00:00
Denny Sheirer
53b44f44e3 Updates gradle build to use version-specific root folder names for OS-specific image products. (#657) 2020-02-16 11:50:20 +00:00
Denny
9af7a184ad Utility for calculating PLL phase lock sync pattern derivatives 2020-02-14 06:11:15 -05:00
Denny Sheirer
9c8d87ec64 #651 Updates audio broadcaster to decrement pending replay count so that pending recordings don't cause a memory leak when the streaming server is not available. (#656) 2020-02-09 10:54:46 -05:00
Denny Sheirer
4c34968d28 #654 Warn users when USB bus speeds are exceeded. (#655)
Updates logging to track max usb speeds per bus and warns user when any USB bus combined tuner data rates exceeds 70% of the max bus rate.
2020-02-09 10:51:55 -05:00
Denny Sheirer
2d71f5173a #652 USB Tuner Error Handling Enhancements (#653)
-Separates USB timeout event processing to a dedicated thread
-Updates USB transfer buffer processor to better detect errors and auto-restart on error (max 3 times)
-Updates Tuner to add an error state and SourceManager to not select tuners with an error state
-Updates ChannelProcessingManager to auto-shutdown channels sourced from tuners set with error state
-Improves logging of USB related errors.
2020-02-09 05:40:04 -05:00
Denny Sheirer
2e942113c6 Resolves #644 NoClassDefFound error when Icecast metadata updater runs. Updates build to version 0.4.0 Beta 4 (#645) 2020-01-12 04:57:38 -05:00
Denny Sheirer
e20540ccc6 #630 Update gradle build to allow runtime image builds without locally installed JDKs. Updates build version to 0.4.0 beta 3 (#643) 2020-01-11 07:01:17 -05:00
Denny Sheirer
8d7e0e9f46 #641 Updates P25 Talkgroup and Radio Id valid ranges to allow value of 0. (#642) 2020-01-11 06:13:44 -05:00
Denny Sheirer
cc5d94f58d #639 Updates all streaming metadata to include radio identifier value as the from value. (#640) 2020-01-11 06:06:08 -05:00
Denny Sheirer
26197e433c #576 P25 Activity Summary Hex and Decimal Network Values (#638)
* #576 Updates P25 activity summaries to list values in hex and decimal.  Resolves issue with P25 explicit channel uplink frequency calculations.  Resolves issue with Motorola base station id messages and traffic channel messages.  Resolves issue with RFSS link control message control channel frequency calculations.  Resolves issue with error when using recording tuners.
2020-01-11 05:33:38 -05:00
Denny Sheirer
f54b4dfd0e 576 Update P25 Activity Summary To Provide Network Values in Hex and Decimal (#637)
* #576 Updates P25 activity summaries to list values in hex and decimal.  Resolves issue with P25 explicit channel uplink frequency calculations.  Resolves issue with Motorola base station id messages and traffic channel messages.  Resolves issue with RFSS link control message control channel frequency calculations.  Resolves issue with error when using recording tuners.
2020-01-11 05:23:47 -05:00
Denny Sheirer
085ba52294 #632 Resolves issue with audio recordings and from identifiers stemming from changes to the way radio IDs are handled. (#634) 2020-01-05 15:48:47 -05:00
Denny Sheirer
b8c24680a5 Resolves #628. Adds P25 talkgroup alias identifier conversions to radio identifiers for any talkgroups or ranges that have values greater than 65,535. Updates playlist version to 4. (#629) 2019-12-22 08:07:47 -05:00
Denny Sheirer
c658582157 Resolves #620. Separates radio identifiers from talkgroups for APCO-25. Updates alias editor with two new options for radio id and radio id range. (#627) 2019-12-22 07:30:48 -05:00
Denny Sheirer
83e518d503 Resolves #625. Updates handling of recording tuners. (#626) 2019-12-21 09:22:04 -05:00
Denny Sheirer
2163d0f822 Update README.md 2019-12-21 08:38:41 -05:00
Denny Sheirer
34c920eede Update README.md 2019-12-21 08:32:54 -05:00
Denny Sheirer
35b0b5ef9b Resolves #623 issue with P25 channels where uplink/downlink use different frequency bands. (#624) 2019-12-21 07:08:05 -05:00
Denny Sheirer
08672c33bd Update README.md 2019-12-20 05:46:24 -05:00
Denny Sheirer
e2651d6c7c Resolves #621 P25 Phase 2 Audio Streaming issue. (#622) 2019-12-20 04:55:37 -05:00
Denny Sheirer
851a4e12d2 Creates StuffBitsMessage to account for processing tail bits in P25 control channel stream. (#618) 2019-12-15 14:56:31 -05:00
Denny Sheirer
b7c66ec844 Updates build version to 0.4.0 beta 2. (#617)
Updates radio reference library to 15.1.2 to resolve issue with logback config collision.
Updates OS build names to better reflect processor types: x86_64 (64-bit) or x86_32 (32-bit)
2019-12-15 07:12:26 -05:00
Denny Sheirer
7522a3a820 Resolves Icecast HTTP metadata updating issue. Resolves issue with Shoutcast V2 metadata not correctly wrapped in xml tag. (#615) 2019-12-15 06:25:51 -05:00
Denny Sheirer
6a0402d1cf Resolves #609 P25 Phase 2 call events are not chaining together and are causing streaming events in the event panel. (#614) 2019-12-13 09:01:40 -05:00
Denny Sheirer
5309af84f7 Resolves #612 P25P2 bit recording filenames indicated incorrect decoder type. (#613) 2019-12-13 05:38:06 -05:00
Denny Sheirer
8d8d77fa11 Resolves #610. P25P2 Editor Doesn't accept scramble parameter values. (#611) 2019-12-13 05:18:30 -05:00
Denny Sheirer
284cf07e97 Update README.md
Adds link to Discord server
2019-11-25 20:05:35 -05:00
Denny Sheirer
16414c7585 Update README.md 2019-11-24 06:18:07 -05:00
Denny Sheirer
70c9eed0bf Update README.md 2019-11-23 16:40:59 -05:00
Denny Sheirer
f49b1fef17 Update README.md 2019-11-23 16:40:03 -05:00
Denny Sheirer
3fe070987a Resolves issue with clunky process for adding recording tuners. (#605) 2019-11-23 12:55:12 -05:00
Denny Sheirer
00d5610213 Resolves issue with the multi-frequency tuner source and P25/MPT1327 (#603)
Resolves issue with the multi-frequency tuner source and P25/MPT1327 (#603) rotating channel frequency configurations failing to maintain lock
on the channel.

Converted the ChannelRotationMonitor from using identifier updates to
now using DecoderStateEvents so that the ChannelState can supply a
steady stream of channel state events to the monitor.
2019-11-23 10:19:23 -05:00
Denny Sheirer
d3c1a605df Resolves issue with application version display in title bar (#601) 2019-11-22 09:47:09 -05:00
Denny Sheirer
85df151a96 Updates map tile fetcher to use TLSv1.2 when connecting to (#599)
openstreetmap.  Java13 uses TLSv1.3 by default and that's not supported
by the tile server.
2019-11-22 09:21:28 -05:00
Denny Sheirer
8915797aac Updates gradle build to use gradle 6 and Java 13.0.1 (#596) 2019-11-19 19:41:01 -05:00
Denny
03a5d71a95 Updates recording tuner to accept center frequency commands. 2019-11-18 19:42:01 -05:00
Denny Sheirer
4158d4ac10 Resolves #570 map tile data not downloading.
Also resolves issue with the default map loading icon pointing to an old image reference.
2019-11-17 11:41:41 -05:00
Denny Sheirer
f934676bd0 #296 APCO25 Phase II Decoder Implementation (#589)
P25 Phase 2 Decoder implementation.
2019-11-17 06:56:52 -05:00
Denny
d5b802e794 Updates next version to 0.4.0 beta 1. 2019-02-17 14:51:57 -05:00
Denny Sheirer
139227e46d Resolves #535 (#540)
Updates Icecast HTTP (2.4) streaming client to perpetually attempt to
reconnect to the server, even if there are (temp) errors.
2019-02-17 06:12:11 -05:00
Denny Sheirer
2394d51a51 Resolves #537 (#539)
Updates application title bar with currently displayed tuner.
2019-02-17 05:49:26 -05:00
Denny Sheirer
d9fa2bea5b Resolves #533. Updates broadcastify stream editor to use new (#538)
radio reference client library and adds support for storing user
credentials in user preferences.

Removes legacy apache axis SOAP and WSDL libraries calls to radio
reference web services -- not required by the new library.
2019-02-17 05:34:31 -05:00
Denny Sheirer
0cb360eeed Resovles #531 updates gradle build script to remove extra jfx runtimes (#532) 2019-02-02 15:17:11 +00:00
Denny Sheirer
ea472f873f Resolves #517 NPE thrown by TalkgroupRangeEditor (#530) 2019-02-02 14:24:23 +00:00
Denny Sheirer
8cbdbd527e Resolves #525 NPE in P25 activity summary report. (#529) 2019-02-02 13:40:57 +00:00
Denny Sheirer
ff0d893bd9 Updates build script to use latest beryx runtime zip plugin and adds (#528)
validation to check for each of the platform-specific JDKs before
executing the runtimeZip task.
2019-02-02 13:37:09 +00:00
Denny
7b924d0486 Removes debug logging 2019-01-27 20:21:46 -05:00
Denny
712eb07f4b Updates build to 0.4.0 alpha 8 2019-01-27 19:59:04 -05:00
Denny Sheirer
d5c3ecc7df Resolves #519 (#520)
- Clears stale patch groups
- Reworks the audio playback panel label update code to properly update
  talkgroups and aliases in concert with the audio playback.
- Removes code that was truncating playback aliases at 32 characters.
2019-01-28 00:58:01 +00:00
Denny Sheirer
c4bf089667 502 icecast http connect error (#518)
* Resolves #502

Resolves issue with connecting to icecast http streaming server.

The issue stems from Icecast HTTP (2.4+) servers not sending a full
HTTP OK response (missing header tokens) to a connection request.

Prior to the upgrade to apache mina 2.0.19, we received a specific
exception and handled it and set the status to connected.

After the upgrade, apache mina is now sending an array index out of
bounds exception when it decodes the incomplete http response.

So, we now catch that specific exception, inspect the http response
hex bytes and set the status to connected.
2019-01-27 14:00:57 +00:00
Denny Sheirer
378b03e06e 515 Patch Group Manager Cross Linking of Talk and Patch Groups (#516)
* Stores minimal main application window location and size/layout settings
to allow application to be restored to the same size/location on
restart.

* Removes talkgroup swapping from the patch group manager which may have
been causing talkgroup <> patch group cross-linking on certain systems.
2019-01-27 12:25:08 +00:00
Denny Sheirer
34235382fb 513 persist application layout across restarts (#514)
* Stores minimal main application window location and size/layout settings
to allow application to be restored to the same size/location on
restart.

* Adds column width monitor to all tables in application that stores the
column width settings in the user preferences so that on restarting
the application the table column widths are restored to the previous
widths.
2019-01-27 12:05:20 +00:00
Denny Sheirer
c05aff0768 Updates alias controller so that when adding an alias to a filtered (#512)
column view it doesn't throw an error.
2019-01-26 13:03:59 +00:00
Denny Sheirer
f0c3e0fd1a Adds logging/warning when alias list contains talkgroups or talkgroup (#511)
range collisions or overlaps.
2019-01-26 11:38:42 +00:00
Denny Sheirer
d601cbda0e Resolves issue with missing case statements in talkgroup format classes. (#509) 2019-01-26 11:11:41 +00:00
Denny Sheirer
2653dc6b38 Removes debug logging. (#508) 2019-01-26 11:02:43 +00:00
Denny Sheirer
48cbbfc656 Updates beryx gradle plugin to resolve issue where launcher script (#503)
did not like '&' ampersand in the execution path.
2019-01-23 09:21:16 +00:00
Denny
d6892b9203 Updates build version to 0.4.0 alpha 7 2019-01-21 04:23:42 -05:00
Denny Sheirer
59f0844fcc 499 Audio Playback Talkgroup Display (#500)
* Resolves issue with non-aliased talkgroup values not displaying in
audio playback (left/right/mono) windows.

* Adds buildSdr build target back into gradle script.
2019-01-21 09:22:31 +00:00
Denny Sheirer
43b285a50a 485 Upgrade Project and Build to Java 11 (#496)
* Updates gradle to 5.1.1

* Updated to run application from intellij using installed Java 11.
Resolves issues with Java 9 deprecations.

* Updates gradle build dependencies and other deprecation issues.

* Updates gradle to produce OS-specific builds.

* Updates the beryx runtime plugin to 1.1.1 to resolve issue with zipping
each of the target distributions.

* Import cleanup

* Resolves issue with Look and Feel error on Max OSX
Resolves issue with building OSX package
Resolves issue with excessive logging about JMBE library.
2019-01-20 18:11:36 +00:00
Denny Sheirer
4e92a6e350 Resolves #494 (#495)
Adds support to AM and FM decoders to record all audio produced by the
decoder.
2019-01-20 15:14:56 +00:00
Denny Sheirer
25d387f3cf 492 Formatted Talkgroup and TalkgroupRange Editors (#493)
* Updates Talkgroup and Talkgroup ranges and editors to support formatted
talkgroup values.

* Updates talkgroup format masks to allow spaces (ie incomplete values)
 in talkgroup values.
2019-01-20 14:30:54 +00:00
Denny Sheirer
52e3d9d20d Adds exception handler to DFT processor to catch InterruptedException (#491)
begin thrown by the FFT library on shutdown.
2019-01-19 10:29:05 +00:00
Denny Sheirer
1e37a63d34 Adds a new JMBE Audio Library preference to the user preferences editor (#489)
so that users can set the library path once and it will persist across
application upgrades so that they do NOT have to copy the library to
their application install with each upgrade.
2019-01-19 10:19:18 +00:00
Denny Sheirer
e51f485a2e Resolves NPE thrown when audio recording metadata is null. (#486) 2019-01-12 09:43:54 -05:00
Denny Sheirer
9378254a38 Updates codebase to use jIconFont icons. (#484)
Removes Ikonli library.
2019-01-12 07:17:51 -05:00
Denny Sheirer
4ab37735e8 Adds support for Motorola Opcode 07 Deny Response message. (#482) 2019-01-12 04:42:52 -05:00
Denny Sheirer
85ca66f656 Update README.md 2019-01-08 04:12:58 -05:00
Denny
d716b0be1c Updates build version to 0.4.0 alpha 6 2019-01-08 04:12:14 -05:00
Denny
70444c1337 Temporarily resolves issue with Ikonli icons that require Java 11. 2019-01-07 04:31:30 -05:00
Denny Sheirer
d90e149021 Adds support to MPT1327 decoder for rotating control channels. (#477) 2019-01-06 07:47:08 -05:00
Denny Sheirer
7510664e00 Update README.md 2019-01-06 07:25:59 -05:00
Denny Sheirer
5481fb7d4d 61 Rotating Control Channel Support - P25 Decoder (#475)
* Initial work on add support for rotating control channels.

* Creates multiple frequency editor control.

* Updates channel source editor to allow user to select multi-frequency
configuration and add multiple frequencies.

* Adds full support for rotating control channels to the P25 channelizer.
Users define multiple frequencies in the channel source configuration.
The decoder monitors the state of the channel for a CONTROL state.  If
the state does not stay in the CONTROL state for a user-specified delay
value, then the decoder rotates to the next frequency in the list.  This
behavior continues until the decoder state once again changes to CONTROL.

This is NOT a 'scanner' feature.
2019-01-06 06:59:04 -05:00
Denny Sheirer
3a39ae76ba Updates alias list to provide a list of aliases for an identifier so that (#474)
we can account for multi-alias identifiers like patch groups and ensure
that patch group alias intentions are carried throughout the system for
recording, streaming, etc.

Updates all consumers of alias list data to ensure it can operate with
a list of aliases versus an assumed single alias.

Refactors APCO25 unit/user status identifiers from a base status class
so that alias list can support status identifiers.
2018-12-31 07:24:25 -05:00
Denny Sheirer
08ea5ab7cb 465 Wave Recording Audio Metadata (#473)
* Initial work on updating wave audio metadata to use identifier collection.

* Cleanup
2018-12-31 06:01:59 -05:00
Denny Sheirer
3fa7401a2b 467 Alias List Update On Alias Delete/Change (#470)
* Updates playlist to fully clean aliases from the alias list when deleted
and to perform a delete and re-add on any alias that changes, to ensure
that the alias list is kept fully up to date.

Removed site id as an alias identifier.

Add support for converting ltr-net uid's to talkgroups in playlist
updater and updated playlist to version 3 to ensure anyone using current
codebase will have their playlists fully updated.

Moved MIN, UniqueID and Site ID to the legacy package and updated
label descriptions to signify that they are no longer supported.
2018-12-31 05:36:54 -05:00
Denny
fce10960fb Updates alias list to remove talkgroup/range alias identifier types. 2018-12-27 08:09:55 -05:00
Denny Sheirer
10b6a08624 Updates alias list to support talkgroup range and patch groups. (#463) 2018-12-27 07:52:38 -05:00
Denny Sheirer
5960343637 Updates PacketMessage to expose to/from identifiers to include the LLID, (#460)
and the to/from IPV4 addresses.
2018-12-27 06:57:18 -05:00
Denny Sheirer
347a71f097 444 Expose Application Directories via User Preferences (#458)
* Refactors DirectoryPreference from PLaylistPreference.
Adds editor to PreferenceEditor for directories.
Organizes preference editor tree.

* Adds recording directory preference to editor and updates recording
manager to dynamically use this property for recordings.

* Adds event logs directory preference to editor and updates event log
manager to dynamically use this property for event logging.

* Adds application log directory preference.  Updates logging to use user
preference for application log directory.  Moves logging initialization
into the main application class and removes file based logging configs
from the logback.xml configuration file.

* Refactors application logging into its own class and adds prefeence
update monitoring to dynamically stop/start the logger in the new
directory location.

* Adds streaming and screen capture directories to the user preferences
editor and updates streaming and screen captures to dynamically adapt
to user changes.
2018-12-27 06:12:03 -05:00
Denny Sheirer
5b5a1431b4 Adds toFront() to channel auto start frame to force the window to the front (#457) 2018-12-25 06:48:26 -05:00
Denny Sheirer
efd811407e Adds tuner preference editor with channelizer type options. Updates (#456)
tuners to use the preference to select either polyphase or heterodyne
channelizers.
2018-12-25 06:43:10 -05:00
Denny Sheirer
b67d4d92dc Identifier Framework and Message/Event Processing Overhaul (#455)
* WIP on new P25 message framer.

* WIP on new P25 message framer.

* Adds new 1/2 and 3/4 rate trellis decoders.  Still trying to chase
down why there is a sync pattern mismatch in the NID buffer queue.

* WIP - new p25 message framer works correctly now.  PDU's are dectected
and decoded using the 1/2 and 3/4 rate trellis decoders.  Packet
Sequences are assembled.  Need to add a new packet sequence message
factory that can detect Motorola Auto Registration Service (ARS)
formatted UDP/ID packets and SNDCP command packets.

* WIP - removes nullify on channel results queue.

* WIP - updates message framer for TSBK 1/2/3 processing.

* WIP removing P25 sync pattern and nid bits from all message parsers.

* WIP - merges identifier framework branch changes into this branch.

* WIP on updating link control words to new format and identifier framework.

* WIP - implements rest of link control words for extended formats

* WIP - initial work on ISP/OSP TSBK message restructuring.

* WIP - adds more TSBK ISP and OSP messages

* WIP - finished updating most of the TSBK ISP and OSP messages.  Converted
all messages to no longer include the NID (nac + dataunitID) so that
each message can simply hold the parsed values.  Removed AliasList as
an argument to each message and updated all messges to use the new
IIdentifer and IAPCO25Channel interfaces.

Removed legacy TDU and LDU link control messages and replaced with a
single LinkControlWord class hierarchy.

P25 decoder state is not yet updated for the new message structure.

PDU message parsing is not fully implemented.

* WIP - adds some Multi-Block trunking control messages with Alternate
and Unconfirmed formats.

* WIP - Fully implements AMBTC and UMBTC PDU message parsers.

Some package restructuring.

* WIP - Resolves Link control parsing in LDU1 and 2 messages.

* WIP - finishes updating TSBK and Link Control messages.  Adds support
for moto link control messages for patch groups.

* WIP - finishes updating TSBK and Link Control messages.  Adds support
for moto link control messages for patch groups.  Adds support for moto
ARS service, IPV4 decoding, and UDP/IP packets.

* WIP - finishes SNDCP packet data with header parsing.  Compressed IP or
UDP headers are not yet supported, but are logged as such.

* WIP - converts all talkgroup identifiers to integers and updates
alias list to create a per-protocol map of talkgroup id's to alias.

Inserts a legacy talkgroup (ltr, p25, passport, mpt1327, mdc, etc.)
conversion utility to convert existing legacy (string) talkgroups to
new integer talkgroup format.

Creates an audio packet manager to insert metadata into audio packets
before streaming packets for playback, recording, and/or streaming.

Creates identifier collection to manage current identifiers in each of
the channel and decoder states.

Creates simplified channel metadata to maintain the now playing display.

Moves channel attributes (alias list, system, site, name) as configuration
identifiers in the channel state.

Many other refactoring and updates.

* WIP - numerous updates to push use of identifier collection throughout
the system.  Updates the channel metadata and audio packet processing
logic.  Implements a large portion of the P25 decode state processing.
Updates traffic channel management.  Adds user preferences for timestamp
and identifier formatting, however doesn't add a user interface yet.

* WIP - initial implementation of user preferences editor window.

* WIP - updates preferences editor window to close and dispose window but
retain javafx event thread running.

* WIP - fully updates p25 decoder state and traffic channel processing to
use the new identifier framework.

Cleans up channel event processing and removes channel model as the sole
broadcaster of channel events.  Channel processing manager now listens
for all start/stop events and requestors dispatch event directly to the
channel processing manager.

Resolves issue in airspy that was causing user interface to lock-up.  The
issue appears to occur when the dongle is plugged into a usb port that
can't fully support the data rate.  sdrtrunk now recognizes these errors
and warns the user that they should use another usb port.

* WIP - updates alias action manager and adds new talkgroup range alias identifier.

Updates playlist to incorporate a version number so that the playlist
updater only runs when needed, to update a playlist to the correct
version format.

Updates user preferences to use the google event bus to broadcast
preference update notifications to remove the need for listeners to
register directly on the user preferences instance.

* WIP - updates alias id editors to flag invalid values and moves legacy
alias ids to legacy package.

Updates event logging configuration to add traffic channel decode events
and decoded message logging.  Removes binary message logging since that
is now replaced with demodulated bitstream recording.

* Removes system properties from user preferences.  Preferences are stored
in the OS-dependent settings store (windows - registry)

* Updates MapService to use new PlottableDecodeEvent instead of monitoring
all of the decoded messages.

Updates Fleetsync decoder and related messages to identifier framework.

* Updates LTR-Net, Fleetsync and LJ1200 decoders to new identifier
framework and adds support for user preferences for formatting of
LTR-Net and fleetsync talkgroup identifiers.

Breaks LTR-Net messages into various message types and uses a new
message factory.

Removes alias list from message processing for ltr-net, fleetsync and
lj1200.

* Updates LTR-Standard messages to Identifier framework.

* Removes Plottable and IPlottable from codebase.

* wip

* WIP on MPT-1327 messages.

* Updates MPT1327 decoder to identifier framework and new traffic channel
manager.  This decoder still needs to be updated with a new message
parser factory and a sync detector like what is now used for P25.

* Updates MDC1200 decoder and message to identifier framework.

* Updates Tait1200 and Passport decoders to identifier framework.

* Merges changes from master branch.

* Removes legacy alias support classes.  Updates passport message processor
to only pass valid messages.  Adds support to playlist updater for
converting passport mobile ids to become passport talkgroup values.

* Updates P25 decoder state and channel state to better track allocated
traffic channels.  Resolves issue in timestamp manager for trackig
message timestamps. Resolves issue in airspy tuner that was causing
the tuner to stop sending samples to the application.

* Update P25 Decoder state to process SNDCP management messages and
PDU messages.

Updates P25 activity summary to display network and site details.

Resolves issue with overlay panel that prevented enabled channels from
rendering correctly when zoomed in.

* Creates a new FilePreferences as part of the user preferences to begin
the transition of SystemProperties over to user preferences and consolidate
file preferences in one location.

Updates playlist manager to use the new file preferences and to use
default.xml as the new default playlist name, following conversion of
a playlist_v2.xml format to the new format.

In the near future, the user will be able to edit file locations and to
create/use other playlists.

Resolved an issue with all decoder states where not all identifiers were
being included in decode events.
2018-12-24 09:08:34 -05:00
whelgeson
735fca16d6 Fix for issue #441 Audio Recording Stops After Encountering Error (#449)
* Fix for issue #441.
Method doc reads that the method is thread-safe, but there exist no locking to ensure thread safety on call into recycle method. Modifying the decrementUserCount method to block other callers to ensure thread-safe access.

This appears to be a hot area of code and there may be a performance hit by doing this, please double check my work here.

* Moving synchronized to recycle method as it's accessed by two different methods that could potentially cause an unsafe access race condition.

* Revert - synchronizing recycle does not protect against multiple recycle calls on the same object.
2018-12-16 19:12:41 -05:00
whelgeson
72fe72c833 Fixing issue #353 Forward Slash in site or channel name causes recording error (#448)
* Fixing issue #353
Moved replaceIllegalCharacters method into StringUtils.
Modified classes that write out to disk to call this method when saving a file.

* Implementing suggested changes from comments in PR #448
2018-12-16 19:10:56 -05:00
Denny Sheirer
4a4d1d4b2e Merge pull request #447 from whelgeson/440-Update-java4usb-library-to-1.3
Bumping usb4java to 1.3.0
2018-12-15 04:59:08 -05:00
Denny Sheirer
2ed7074c0d Merge pull request #446 from whelgeson/442-Runtime-error-on-Java-11
Bumping Jide to 3.6.18 to fix Java 11 reflections error
2018-12-15 04:53:01 -05:00
billh
b5a895c266 Bumping usb4java to 1.3.0 2018-12-13 23:28:18 -06:00
billh
b57d7b5c0e Bumping jide to 3.6.18 to fix Java 11 reflections error 2018-12-13 23:20:32 -06:00
Denny Sheirer
cb12d314d0 Merge pull request #436 from DSheirer/387-audio-10-minute-time-limit
Resolves #387 (P25) 10 second/10 minute audio recording time limit.
2018-10-08 04:59:10 -04:00
Denny
eb79d9e037 Resolves #387 10 second/10 minute audio recording time limit.
Updated audio packet wave recorder to correctly dequeue audio packets
to ensure that the overflowable buffer queue accounting process was
working correctly.

Updated overflowable buffer queue's poll() method to correctly decrement
the queue size counter.

Resolved issue where the mutable metadata was being prematurely reset
and causing the end audio packet to be mis-identified.  This resulted
in the recording manager not stopping the recording on command with the
timeout mechanism kicking in after a brief delay.
2018-10-08 04:58:21 -04:00
Denny
d95c78c0f1 Updates version to 0.4.0 alpha 5 2018-09-23 05:51:28 -04:00
Denny Sheirer
aee5ece8d2 Merge pull request #430 from DSheirer/429-polyphase-channelizer-25khz-channel-rate
429 polyphase channelizer 25khz channel rate
2018-09-23 05:50:18 -04:00
Denny
ba358a7d48 Adjusted costas loop gain values. Updated channel filter values to mitigate adjacent channel interference. 2018-09-23 05:34:41 -04:00
Denny
09b209496b Resolves issue with NPE in 3/4 rate decoder. 2018-09-22 09:19:15 -04:00
Denny Sheirer
cc209683bd Merge pull request #428 from DSheirer/377-npe-in-trellis-decoder
377 NPE in P25 3/4 Rate Trellis Decoder
2018-09-22 02:53:16 -04:00
Denny
2771c28dba Resolves issue with NPE in 3/4 rate decoder. 2018-09-22 02:52:36 -04:00
Denny
d752917073 Resolves #427. Moves the module(s) reset operation to the stop() method
so that the modules are reset after they are shut down, in order to
prepare for processing chain reuse.

Previously, the modules were reset upon startup, but after any traffic
channel metadata had already been transferred to the channel state,
causing the metadata to be lost and allowing initial audio packets to
stream without any metadata and related streaming/monitoring rules.
2018-09-20 04:01:45 -04:00
Denny
28bc02e172 Updates channel state to ensure teardown processing is completed during
a call end and/or during a commanded stop.
2018-09-19 04:25:37 -04:00
Denny
0f6044d48b Updates mutable metadata to reset the buffer overflow flag between uses. 2018-09-18 19:15:06 -04:00
Denny Sheirer
58ecb83e2c Merge pull request #425 from DSheirer/417-channel-overflow-state-processing
417 Channel Overflow State Processing - Part 2
2018-09-16 10:23:15 -04:00
Denny
9e1de922e4 Resolves issue with overflow state processing. Displays the overflow
state in the Message field of the channel metadata table column instead
of displaying it in the channel state column.
2018-09-16 10:22:27 -04:00
Denny Sheirer
84d0b827d8 Merge pull request #422 from DSheirer/421-nbfm-25-khz-channel-bandwidth
421 Add 25 kHz Channel Bandwidth Support to NBFM Decoder
2018-09-16 07:22:38 -04:00
Denny
a17132be0d Updates the NBFM decoder to allow user to select between 12.5 and 25.0
kHz channel bandwidth so that 25 kHz channels can be demodulated correctly.
2018-09-16 07:21:14 -04:00
Denny Sheirer
dae68515a5 Merge pull request #420 from DSheirer/419-heterdyne-channelizer-center-frequency-tuning
419 Heterodyne Channelizer Center Frequency Calculations
2018-09-16 06:04:09 -04:00
Denny
0aaec8ff54 Updates the heterodyne channelizer's center frequency calculator to
only update the center frequency when needed and to place the set of
decoding channels adjacent to the right side of the tuner's center
frequency when the complete set of channels fit into the usable half
bandwidth of the tuner.
2018-09-16 06:02:46 -04:00
Denny Sheirer
001883edc2 Merge pull request #418 from DSheirer/417-channel-overflow-zombie-state
417 Traffic Channels in Buffer Overflow state do not tear down correctly
2018-09-16 05:23:05 -04:00
Denny
335fb51456 Updates buffer overflow handling to occur coincident to other channel
states rather than being a channel state itself.  This was preventing
traffic channels that overflow from being torn down correctly.
2018-09-16 05:21:46 -04:00
Denny Sheirer
e94b6ae172 Merge pull request #416 from DSheirer/415-overflow-state
415 Buffer Overflow State Listener Registration
2018-09-14 06:46:34 -04:00
Denny
785125da4f Correctly implements the buffer overflow listener registration so that
decoding channels can be notified when the internal buffer goes into
and out of overflow state.
2018-09-14 06:45:37 -04:00
Denny
81b8f5a423 Updates build to version 0.4.0 alpha 4 2018-09-12 06:23:09 -04:00
Denny Sheirer
bf186a7408 Merge pull request #414 from DSheirer/405-airspy-tuner-waterfall-freeze
405 Airspy Spectrum/Waterfall Freezes
2018-09-12 06:20:36 -04:00
Denny
43fc326f93 Resolves #405
Adds 500 ms delay to initial registering for samples from all tuners to
feed the spectral display/waterfall.  The existing approach of immediately
registering for samples was causing the airspy tuner to lockup
aperiodically.  Investigation via debugger didn't show any application
thread locks ... usb master processor was continuing to service libusb
timeouts.  Unable to debug internal airspy processes.  Adding the delay
to startup seems to be a usable solution.
2018-09-12 06:19:11 -04:00
Denny Sheirer
7cdbb75b42 Merge pull request #413 from DSheirer/375-poor-p25-decode-performance
375 P25 Decode Performance
2018-09-10 04:22:40 -04:00
Denny
96a56cab68 Resolves #375.
Reverts PLL gain values to version 0.3.4beta2 values to restore P25
decoder performance.

This change in conjuction with recent channel sample rate change should
restore P25 channel decoding to comparable levels from 0.3.4b2.
2018-09-09 09:55:40 -04:00
Denny Sheirer
29d4b36cf7 Merge pull request #412 from DSheirer/411-variable-channel-sample-rates
#411 Update Tuner Source Manager to provide variable sample rate channels
2018-09-09 09:50:11 -04:00
Denny
b15a3e59a0 Resolves #411
Updates decoder types to specify channel sample rate and pass/stop
frequencies for requested channels.  Updates tuner channel source
managers to accept a channel specification for channels that are
allocated.
2018-09-09 09:49:05 -04:00
Denny Sheirer
9950e46e5a Merge pull request #408 from DSheirer/406-tuner-sample-delay-buffer
406 Tuner Sample Delay Buffer
2018-09-09 08:47:17 -04:00
Denny
570321da3e Implements a complex sample delay buffer integrated into the tuner
channel manager so that channel source requests can have a start
timestamp specified and the channel can be preloaded with samples from
the delay buffer.  If no timestamp is specified, current time is assumed.

This feature requires corresponding updates to any decoder that wishes
to implement the timestamped sample preloading functionality.
2018-09-09 08:46:21 -04:00
2721 changed files with 294357 additions and 95193 deletions

38
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: Bug Report
about: Create a report to help us improve sdrtrunk
title: ''
labels: bug
assignees: ''
---
**sdrtrunk Version**
Indicate which sdrtrunk version you are using. Use 'master-branch' if you are running the latest code.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Application Log**
If applicable, include either the full application log,or a snippet of the error logging.
**Desktop (optional - complete the following information):**
- OS: [e.g. iOS]
- CPU Cores: [e.g. 4 cores]
- RAM:[e.g. 16GB]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,16 @@
---
name: How-To Question or Does The Software Support xxx
about: End user question or support discussion
title: STOP - Don't Use Issue Reporting to Post End-User Questions!!!
labels: ''
assignees: ''
---
STOP !!!!
GitHub issues are for reporting software bugs or requesting enhancements.
If you have a question about how to use the software, or if you want to know if sdrtrunk supports a protocol, tuner, or other aspect, please post your question in one of the Support forums.
Visit: https://github.com/DSheirer/sdrtrunk/wiki

34
.github/workflows/gradle.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up JDK 20
uses: actions/setup-java@v3
with:
java-version: '20'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Build with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: clean build

47
.github/workflows/nightly.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
# Create nightly release for Linux, Mac and Windows using the Linux runner.
name: Nightly Release
on:
push:
branches: [ master ]
# Don't run nightly build for pull requests - uncomment to test changes to this action within scope of the PR review
# pull_request:
# branches: [ master ]
jobs:
nightly:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 20
uses: actions/setup-java@v3
with:
java-version: '20'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Build Linux and Mac releases with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: runtimeZipOthers -PprojectVersion=nightly
- name: Build Windows release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: runtimeZipWindows -PprojectVersion=nightly
- name: Create Build Info file
run: |
echo -e "ref: $GITHUB_REF \ncommit: $GITHUB_SHA\nbuild: $(date +"%Y-%m-%dT%H:%M:%SZ")" > build/image/build_info.txt
- name: Add build artifacts to nightly release
uses: pyTooling/Actions/releaser@main
with:
tag: nightly
rm: false
token: ${{ secrets.GITHUB_TOKEN }}
files: |
build/image/*.zip
build/image/build_info.txt

2
.gitignore vendored
View File

@@ -17,7 +17,7 @@ out/
*.class
*.log
# Package Files #
*.jar
#*.jar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

9
.idea/compiler.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel>
<module name="sdr-trunk_main" target="1.8" />
<module name="sdr-trunk_test" target="1.8" />
</bytecodeTargetLevel>
</component>
</project>

View File

@@ -2,8 +2,11 @@
<dictionary name="denny">
<words>
<w>bahroo</w>
<w>basebanded</w>
<w>broadcastify</w>
<w>correlator</w>
<w>deinterleave</w>
<w>descrambled</w>
<w>dinf</w>
<w>esnid</w>
<w>fleetsync</w>
@@ -23,6 +26,7 @@
<w>shoutcast</w>
<w>streamable</w>
<w>talkgroup</w>
<w>talkgroups</w>
<w>tgid</w>
<w>ultravox</w>
<w>wacn</w>

View File

@@ -1,14 +0,0 @@
<component name="libraryTable">
<library name="imports">
<CLASSES>
<root url="jar://$PROJECT_DIR$/imports/jmbe-interface-0.3.3.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/java-lame-3.98.4.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/radioreference-14.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/wsdl4j-1.5.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/commons-math3-3.6.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libresample4j-0.1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

6
.idea/misc.xml generated
View File

@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_20_PREVIEW" project-jdk-name="liberica-20" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

10
.idea/modules.xml generated
View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk_main.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk_main.iml" group="sdr-trunk" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk_test.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk_test.iml" group="sdr-trunk" />
</modules>
</component>
</project>

12
.idea/vcs.xml generated
View File

@@ -1,16 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="IssueNavigationConfiguration">
<option name="links">
<list>
<IssueNavigationLink>
<option name="issueRegexp" value="#(\d+)" />
<option name="linkRegexp" value="https://github.com/DSheirer/sdrtrunk/issues/$1" />
</IssueNavigationLink>
</list>
</option>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -1,3 +1,18 @@
0.4.0 20200404
- Release includes embedded Java 14 & JavaFX 13 runtime
- Adds Polyphase Channelizer with 2x channel oversampling and redesigned source management
- Adds P25 Phase 2 decoder
- Adds P25 radio identifier aliasing
- JMBE library 1.0.4 with support for AMBE tone metadata
- New JavaFX User Preferences dialog
- HackRF tuner enhanced (sample rates and saturation issues)
- Adds support for Airspy mini tuner
- Redesigned audio sub-system that uses AudioSegments
- USB tuner bus saturation management/monitoring
- Bitstream (.bits) recording
- MP3 Audio Recording
- Numerous bug fixes
0.3.4 20180418
- New P25 C4FM decoder that uses Differential QPSK decoder instead of FM demodulation with 4FSK.
- Adds channel auto-start and ordering capability with startup dialog allowing user to invoke or bypass channel

View File

@@ -1,78 +1,33 @@
![Gradle Build](https://github.com/dsheirer/sdrtrunk/actions/workflows/gradle.yml/badge.svg)
![Nightly Release](https://github.com/dsheirer/sdrtrunk/actions/workflows/nightly.yml/badge.svg)
# sdrtrunk
A cross-platform java application for decoding, monitoring, recording and streaming trunked mobile and related radio protocols using Software Defined Radios (SDR).
* [Getting Started](https://github.com/DSheirer/sdrtrunk/wiki/GettingStarted_V0.3.0)
* [User's Manual Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual_V0.3.0)
* [Help/Wiki Home Page](https://github.com/DSheirer/sdrtrunk/wiki)
* [Getting Started](https://github.com/DSheirer/sdrtrunk/wiki/Getting-Started)
* [User's Manual](https://github.com/DSheirer/sdrtrunk/wiki/User-Manual)
* [Download](https://github.com/DSheirer/sdrtrunk/releases)
* [Support](https://groups.google.com/forum/#!forum/sdrtrunk)
* [Support](https://github.com/DSheirer/sdrtrunk/wiki/Support)
![sdrtrunk Application Overview - Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/v0.3/images/ApplicationOverview_V0.3.0.png)
**Figure 1:** sdrtrunk **Version 0.3.0** Application Screenshot
![sdrtrunk Application](https://github.com/DSheirer/sdrtrunk/wiki/images/sdrtrunk.png)
**Figure 1:** sdrtrunk Application Screenshot
# End User Instructions:
If you simply want to download and run the program, please follow these instructions.
## Install Java 8 (or newer)
## Download the latest sdrtrunk release
## Download the Latest Release
All release versions of sdrtrunk are available from the [releases](https://github.com/DSheirer/sdrtrunk/releases) tab.
**(final)** These versions have been tested and are the current release version.
* **(alpha)** These versions are under development feature previews and likely to contain bugs and unexpected behavior.
* **(beta)** These versions are currently being tested for bugs and functionality prior to final release.
* **(final)** These versions have been tested and are the current release version.
**(beta)** These versions are currently being tested for bugs and functionality.
## Download Nightly Software Build
The [nightly](https://github.com/DSheirer/sdrtrunk/releases/tag/nightly) release contains current builds of the software
for all supported operating systems. This version of the software may contain bugs and may not run correctly. However,
it let's you preview the most recent changes and fixes before the next software release. **Always backup your
playlist(s) before you use the nightly builds.** Note: the nightly release is updated each time code changes are
committed to the code base, so it's not really 'nightly' as much as it is 'current'.
## Run the application
Either double-click on the downloaded file (if supported on your operating system) or open a terminal/command window
and change to the directory where you downloaded the release file and type:
```
java -jar downloaded-jar-filename
```
Note: replace _downloaded-jar-filename_ with the actual name of the sdrtrunk release version that you downloaded
## Optional - P25 Audio
If you're using sdrtrunk with a P25 trunked radio system, the [JMBE](https://github.com/DSheirer/sdrtrunk/wiki/JMBE) wiki page contains instructions
for downloading the JMBE audio library source code and compiling the JMBE library. Copy the resulting JMBE audio library
jar file to the same folder containing the sdrtrunk application to use the library with sdrtrunk.
# Developer Instructions:
If you're interested in modifying and/or compiling the source code, please follow these instructions to use gradle to compile the code.
## Build the project
sdrtrunk uses gradle as the build system. You can build it with locally installed gradle or if you do not have/want
to install gradle you can use preconfigured linux/windows wrapper.
### Build with locally installed gradle 4.3.1
```
gradle clean buildSdr
```
### Build with preconfigured wrapper for linux/windows
Linux
```
./gradlew clean buildSdr
```
Windows
```
gradle.bat clean buildSdr
```
This would add gradle, download all project dependencies and build JAR
## Development
All dependencies/versions are controlled from build.gradle.
To change the new release version tag of artifact - change property:
```
version = '0.3.2'
```
## Run SDRTrunk
SDRTrunk is packed into single uber-jar file. There is need to have folders with dependencies and
adding them with classpath. Just run with java.
### Use Java8
```
java -jar build/libs/sdr-trunk-all-0.3.2.jar
```
## Minimum System Requirements
* **Operating System:** Windows (~~32 or~~ 64-bit), Linux (~~32 or~~ 64-bit) or Mac/Linux (64-bit, 10.14 or higher)
* **CPU:** 4-core
* **RAM:** 8GB or more (preferred). Depending on usage, 4GB may be sufficient.

View File

@@ -0,0 +1,36 @@
Auto-generating Java code from SDRPlay API using jextract.
Note: the api headers in the 3.11 folder are equivalent to the 3.08 headers. The only
difference from the 3.07 headers is the addition of the boolean 'valid' flag to DeviceT structure.
1. Download JDK19 compatible build of jextract JDK: https://jdk.java.net/jextract/
2. If generating on windows platform, modify the sdrplay_api.h to remove the windows
pieces of the file. Specifically:
2a. Comment out these lines but leave the *HANDLE typedef:
//#if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
2b. Remove the '_SDRPLAY_DLL_QUALIFIER' from in front of the method declarations
2c. Change the 3.11 version string to 3.08 either in the header file, or in the generated java class
3. Open command prompt to the root source code where the generated files should be placed:
..\SDRtrunk\sdrplay-api\src\main\java
4. Generate the code:
c:\Users\Denny\Downloads\jdk-19-ea2-panama\bin\jextract "C:\Users\Denny\git\sdrtrunk\sdrplay-api\api\v3_11\sdrplay_api.h" -l libsdrplay_api --source
5. Do this for all versions of the API.

View File

@@ -0,0 +1,229 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.07)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
sdrplay_api_ErrT sdrplay_api_Open(void);
sdrplay_api_ErrT sdrplay_api_Close(void);
sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,78 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,45 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_60 20 // Number of LNA states when using AM Port 2 between 12 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 26 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -0,0 +1,230 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.08)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
unsigned char valid;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate, double newSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// // Comman API function definitions
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Open(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Close(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
//
// // Device API function definitions
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate, double newSampleRate);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
// sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
// sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,78 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,45 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_60 20 // Number of LNA states when using AM Port 2 between 12 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 26 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -0,0 +1,230 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.11)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
unsigned char valid;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate, double newSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
sdrplay_api_ErrT sdrplay_api_Open(void);
sdrplay_api_ErrT sdrplay_api_Close(void);
sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate, double newSampleRate);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,79 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
sdrplay_api_DeviceFailure = 4,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,46 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_50 20 // Number of LNA states when using AM Port 2 between 12 and 50MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_50_60 25 // Number of LNA states when using AM Port 2 between 50 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 22 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -1,28 +1,182 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
}
}
import java.text.SimpleDateFormat
apply plugin: 'java'
apply plugin: 'idea'
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
/**
* Instructions for building/compiling the sdrtrunk application.
*
* Prerequisites:
* Install and configure an OpenJDK version 19+ that includes the JavaFX modules (e.g. Bellsoft Liberica JDK)
* - Optional: install and configure Gradle 7.6+
*
* Scenario 1: run the application via gradle command line from the source code root directory:
* command: ./gradlew run
*
* Scenario 2: create an application release for the current operating system
* command: ./gradlew runtimeZipCurrent
* Note: release image is located in the /build/image/ directory
*
* Scenario 3: create releases for Linux and OSX operating systems using downloaded JDKs
* command: ./gradlew runtimeZipOthers
* Note: release images are located in the /build/image/ directory
*
* Scenario 4: create release for Windows operating system using downloaded JDK
* command: ./gradlew runtimeZipWindows
* Note: release image is located in the /build/image/ directory
*/
plugins {
id 'application'
id 'java'
id 'idea'
id 'org.beryx.runtime' version '1.12.7'
}
repositories {
jcenter()
mavenCentral()
maven { url "https://jitpack.io" }
}
version = '0.4.0-alpha.3'
sourceCompatibility = 1.8
//Version is defined in gradle.properties so that we can CLI override it for nightly builds.
version = project.findProperty('projectVersion')
//Java 20 is required for this version of the Project Panama preview/incubator feature
java {
toolchain {
languageVersion = JavaLanguageVersion.of(20)
}
}
sourceSets {
main.java.srcDirs 'src/main'
test.java.srcDirs 'src/test'
}
test {
useJUnitPlatform()
}
dependencies {
// JUnit Tests
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.assertj:assertj-core:3.23.1'
testImplementation('org.junit.jupiter:junit-jupiter-api:5.9.0')
testImplementation 'org.mockito:mockito-core:4.8.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
//Jitpack imports
implementation 'com.github.dnault:libresample4j:master'
implementation 'com.github.DSheirer.jmbe:jmbe-api:1.0.0'
implementation 'com.github.nwaldispuehl:java-lame:v3.98.4'
//mavenCentral/jcenter imports
implementation 'ch.qos.logback:logback-classic:1.4.5'
implementation 'ch.qos.logback:logback-core:1.4.5'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0'
implementation 'com.fazecast:jSerialComm:2.9.3'
implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1'
implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0'
implementation 'com.github.jiconfont:jiconfont-swing:1.0.1'
implementation 'com.github.wendykierp:JTransforms:3.1'
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'com.jidesoft:jide-oss:3.6.18'
implementation 'com.miglayout:miglayout-swing:11.0'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'commons-io:commons-io:2.11.0'
implementation 'eu.hansolo:charts:1.0.5'
implementation 'io.github.dsheirer:radio-reference-api:15.1.9'
implementation 'javax.usb:usb-api:1.0.2'
implementation 'net.coderazzi:tablefilter-swing:5.5.4'
implementation 'org.apache.commons:commons-compress:1.21'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'org.apache.mina:mina-core:2.2.1'
implementation 'org.apache.mina:mina-http:2.2.1'
implementation 'org.controlsfx:controlsfx:11.1.2'
implementation 'org.rauschig:jarchivelib:1.2.0'
implementation 'org.slf4j:slf4j-api:2.0.5'
implementation 'org.usb4java:libusb4java:1.3.0'
implementation 'org.usb4java:usb4java:1.3.0'
implementation 'org.usb4java:usb4java-javax:1.3.0'
implementation 'io.github.dsheirer:libusb4java-darwin-aarch64:1.3.1' //usb4java native lib for OSX M1 cpu
implementation 'pl.edu.icm:JLargeArrays:1.6'
}
def os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem
/**
* This is needed for the JDK19 panama and vector API ... until it moves out of incubation or preview
*/
tasks.withType(JavaCompile) {
options.compilerArgs.add("--enable-preview") //Panama Foreign Function/Memory is preview in JDK 19
options.compilerArgs.add("--add-modules=jdk.incubator.vector") //Needed while Panama Vector API remains in incubator
}
/**
* JVM Arguments for running the application on Windows.
*/
def jvmArgsWindows =
['--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED', //Needed for controls-fx.jar
'--add-exports=java.desktop/com.sun.java.swing.plaf.windows=ALL-UNNAMED', //windows users for JIDE
'--add-modules=jdk.incubator.vector', //Needed while Project Panama API is still in incubator
'--enable-preview', //Project Panama Vector & Foreign Function APIs remain in incubator
'--enable-native-access=ALL-UNNAMED',
'-Djava.library.path=c:\\Program Files\\SDRplay\\API\\x64'] //Allows Project Panama Foreign Function access to system library
/**
* JVM Arguments for running the application on Linux.
*/
def jvmArgsLinux =
['--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED', //Needed for controls-fx.jar
'--add-modules=jdk.incubator.vector', //Needed while Project Panama API is still in incubator
'--enable-preview', //Project Panama Vector & Foreign Function APIs remain in incubator
'--enable-native-access=ALL-UNNAMED',
'-Djava.library.path=/usr/local/lib'] //Allows Project Panama Foreign Function access to system library
application {
mainClassName = "io.github.dsheirer.gui.SDRTrunk"
if(os.isWindows()) {
applicationDefaultJvmArgs = jvmArgsWindows
}
else {
applicationDefaultJvmArgs = jvmArgsLinux
}
}
jar {
manifest {
attributes (
'Implementation-Title' : 'sdrtrunk project',
'Implementation-Version' : archiveVersion,
'Created-By' : "Gradle ${gradle.gradleVersion}",
'Build-Timestamp' : new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Build-JDK' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']}",
'Build-OS' : "${System.properties['os.name']} (${System.properties['os.arch']} ${System.properties['os.version']}"
)
}
}
idea {
module {
downloadJavadoc = true
@@ -30,46 +184,172 @@ idea {
}
}
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.assertj:assertj-core:3.8.0'
compile fileTree(dir: 'imports', include: '*.jar')
compile 'org.apache.commons:commons-lang3:3.7'
compile 'org.apache.commons:commons-io:1.3.2'
compile 'org.slf4j:slf4j-api:1.7.25'
compile 'ch.qos.logback:logback-core:1.2.3'
compile 'ch.qos.logback:logback-classic:1.2.3'
compile 'com.miglayout:miglayout-swing:5.0'
/**
* Runtime target OS and CPU image names. We append version here so that version details are at end of zip filename.
*/
String targetLinuxAarch64 = 'linux-aarch64-v' + version
String targetLinuxX86_64 = 'linux-x86_64-v' + version
String targetOsxAarch64 = 'osx-aarch64-v' + version
String targetOsxX86_64 = 'osx-x86_64-v' + version
String targetWindowsX86_64 = 'windows-x86_64-v' + version
compile 'org.usb4java:usb4java-javax:1.2.0'
compile 'org.usb4java:usb4java:1.2.0'
compile 'org.usb4java:libusb4java:1.2.0'
compile 'javax.usb:usb-api:1.0.2'
compile 'com.github.wendykierp:JTransforms:3.1'
compile 'pl.edu.icm:JLargeArrays:1.6'
compile 'net.coderazzi:tablefilter-swing:5.3.1'
compile 'com.jidesoft:jide-oss:3.4.3'
compile 'org.apache.mina:mina-core:2.0.16'
compile 'org.apache.mina:mina-http:2.0.16'
compile 'org.apache.axis:axis-jaxrpc:1.4'
compile 'org.apache.axis:axis:1.4'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.3'
compile 'org.kordamp.ikonli:ikonli-javafx:2.1.1'
compile 'org.kordamp.ikonli:ikonli-fontawesome-pack:2.1.1'
/**
* Optional pre-downloaded Java Development Kit (JDK) for each target OS and CPU. These locations are hard-coded to the
* author's development environment, but can be changed to your environment if you want to use this build pattern.
*/
String jdk_base = '/home/denny/java_jdks/'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-20.0.1-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-20.0.1-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-20.0.1-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-20.0.1-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-20.0.1-full'
/**
* Download URLs to download the JDK as part of the gradle build packaging process
*/
def jdk_download_base = "https://download.bell-sw.com/java/20.0.1+10/bellsoft-jdk20.0.1+10-"
def jdk_download_suffix = "-full.tar.gz"
def jdk_download_linux_aarch64 = jdk_download_base + "linux-aarch64" + jdk_download_suffix
def jdk_download_linux_x86_64 = jdk_download_base + "linux-amd64" + jdk_download_suffix
def jdk_download_osx_x86_64 = jdk_download_base + "macos-amd64" + jdk_download_suffix
def jdk_download_osx_aarch64 = jdk_download_base + "macos-aarch64" + jdk_download_suffix
def jdk_download_windows_x86_64 = jdk_download_base + "windows-amd64-full.zip"
/**
* Configures the runtime zip task with additional options/settings.
* @param rt task to configure
* @param jvmArgs to use (windows or linux)
* @return configured task.
*/
def configure(org.beryx.runtime.RuntimeZipTask rt, List<String> jvmArgs) {
//Use the correct set of JVM arguments
rt.extension.launcherData.get().jvmArgs = jvmArgs
//Additional modules to include with auto-detected modules.
//jdk.crypto.ec - needed for HTTPS connections (broadcastify calls & map tile server)
//jdk.incubator.vector - needed for Project Panama foreign function and vector apis
//jdk.accessibility is used with assistive technologies like screen readers
//java.management for JVM resource monitoring
rt.extension.addModules('jdk.crypto.ec', 'jdk.incubator.vector', 'jdk.accessibility', 'java.management')
//Use auto-detected modules and 'add' any specified modules.
rt.extension.additive.set(true)
//Recommended options for reducing/shrinking runtime target image size
rt.extension.addOptions('--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages')
//Runtime images have auto appended version in image zip name. Override to include version in single target image.
rt.extension.imageZip.set(file("$buildDir/image/sdr-trunk.zip"))
}
task wrapper(type: Wrapper) {
gradleVersion = '4.3.1'
}
/**
* Creates a release package for the current operating system.
*
* Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
*
* Usage: gradle runtimeZipCurrent
* Usage: gradlew runtimeZipCurrent (windows - using gradlew)
* Usage: ./gradlew runtimeZipCurrent (linux - using gradlew)
*/
tasks.register('runtimeZipCurrent', org.beryx.runtime.RuntimeZipTask) {rt ->
def arch = System.properties.getProperty("os.arch")
def javaHome = org.gradle.internal.jvm.Jvm.current().getJavaHome().toString()
task buildSdr(type: Jar) {
manifest {
attributes 'Implementation-Title': 'SdrTrunk project',
'Implementation-Version': version,
'Main-Class': 'io.github.dsheirer.gui.SDRTrunk',
'Class-Path': 'jmbe-0.3.2.jar jmbe-0.3.3.jar'
if(os.isWindows()) {
rt.extension.targetPlatform(targetWindowsX86_64, javaHome)
configure(rt, jvmArgsWindows)
}
else if(os.isLinux())
{
if(arch.equals("amd64")) {
rt.extension.targetPlatform(targetLinuxX86_64, javaHome)
}
else if(arch.equals("aarch64")) {
rt.extension.targetPlatform(targetLinuxAarch64, javaHome)
}
configure(rt, jvmArgsLinux)
}
else if(os.isMacOsX())
{
if(arch.equals("amd64")) {
rt.extension.targetPlatform(targetOsxX86_64, javaHome)
}
else if(arch.equals("aarch64")) {
rt.extension.targetPlatform(targetOsxAarch64, javaHome)
}
configure(rt, jvmArgsLinux)
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
/**
* Creates a Windows release package.
*
* Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
*
* Usage: gradle runtimeZipWindows
* Usage: gradlew runtimeZipWindows (windows - using gradlew)
* Usage: ./gradlew runtimeZipWindows (linux - using gradlew)
*/
tasks.register('runtimeZipWindows', org.beryx.runtime.RuntimeZipTask) {rt ->
if(file(jdk_windows_x86_64).exists()) {
rt.extension.targetPlatform(targetWindowsX86_64, jdk_windows_x86_64, [])
}
else {
rt.extension.targetPlatform(targetWindowsX86_64) {
jdkHome = jdkDownload(jdk_download_windows_x86_64)
}
}
configure(rt, jvmArgsWindows)
}
/**
* Creates Linux & OSX release packages.
*
* Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
*
* Usage: gradle runtimeZipOthers
* Usage: gradlew runtimeZipOthers (windows - using gradlew)
* Usage: ./gradlew runtimeZipOthers (linux - using gradlew)
*/
tasks.register('runtimeZipOthers', org.beryx.runtime.RuntimeZipTask) {rt ->
//Linux aarch64
if(file(jdk_linux_aarch64).exists()) {
rt.extension.targetPlatform(targetLinuxAarch64, jdk_linux_aarch64, [])
}
else {
rt.extension.targetPlatform(targetLinuxAarch64) {
jdkHome = jdkDownload(jdk_download_linux_aarch64)
}
}
//Linux x86-64
if(file(jdk_linux_x86_64).exists()) {
rt.extension.targetPlatform(targetLinuxX86_64, jdk_linux_x86_64, [])
}
else {
rt.extension.targetPlatform(targetLinuxX86_64) {
jdkHome = jdkDownload(jdk_download_linux_x86_64)
}
}
//OSX aarch64
if(file(jdk_osx_aarch64).exists()) {
rt.extension.targetPlatform(targetOsxAarch64, jdk_osx_aarch64, [])
}
else {
rt.extension.targetPlatform(targetOsxAarch64) {
jdkHome = jdkDownload(jdk_download_osx_aarch64)
}
}
//OSX x86-64
if(file(jdk_osx_x86_64).exists()) {
rt.extension.targetPlatform(targetOsxX86_64, jdk_osx_x86_64, [])
}
else {
rt.extension.targetPlatform(targetOsxX86_64) {
jdkHome = jdkDownload(jdk_download_osx_x86_64)
}
}
configure(rt, jvmArgsLinux);
}

16
copyright.template Normal file
View File

@@ -0,0 +1,16 @@
******************************************************************************
Copyright (C) 2014-${today.year} Dennis Sheirer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*****************************************************************************

31
gradle.properties Normal file
View File

@@ -0,0 +1,31 @@
#
# ******************************************************************************
# Copyright (C) 2014-2023 Dennis Sheirer
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# *****************************************************************************
#
# Version naming conventions:
# Alpha: maj.min.patch-alpha-build
# Beta: maj.min.patch-beta-build
# Release: maj.min.patch
#
# Example: 0.6.0-beta-5
#
# Note: this is so that the file names for the resultant release build products match the GitLab release asset
# tag name, specifically the dashes inserted before and after the alpha/beta labels.
# See: https://github.com/DSheirer/sdrtrunk/issues/1651
projectVersion=0.6.0

Binary file not shown.

View File

@@ -1,5 +1,25 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-bin.zip
#
# ******************************************************************************
# Copyright (C) 2014-2023 Dennis Sheirer
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# *****************************************************************************
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

305
gradlew vendored
View File

@@ -1,78 +1,132 @@
#!/usr/bin/env sh
#!/bin/sh
#
# ******************************************************************************
# Copyright (C) 2014-2022 Dennis Sheirer
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# *****************************************************************************
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +135,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +143,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

56
gradlew.bat vendored
View File

@@ -1,4 +1,20 @@
@if "%DEBUG%" == "" @echo off
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,19 +25,23 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,38 +65,26 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/images" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/config" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="imports" level="project" />
</component>
</module>

View File

@@ -1,20 +1,24 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
*/
package io.github.dsheirer.alias;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -24,170 +28,474 @@ import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.alias.id.nonrecordable.NonRecordable;
import io.github.dsheirer.alias.id.priority.Priority;
import io.github.dsheirer.alias.id.record.Record;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.util.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Alias provides an aliasing (e.g. name, color, etc) container that is linked to multiple alias identifiers and
* provides a corresponding set of actions related to the alias.
*/
@JacksonXmlRootElement(localName = "alias")
public class Alias
{
private String mList;
private String mGroup;
private String mName;
private int mColor;
private String mIconName;
private List<AliasID> mAliasIDs = new ArrayList<AliasID>();
private List<AliasAction> mAliasActions = new ArrayList<AliasAction>();
private final static Logger mLog = LoggerFactory.getLogger(Alias.class);
public Alias()
{
}
private BooleanProperty mRecordable = new SimpleBooleanProperty();
private BooleanProperty mStreamable = new SimpleBooleanProperty();
private BooleanProperty mOverlap = new SimpleBooleanProperty();
private IntegerProperty mColor = new SimpleIntegerProperty();
private IntegerProperty mPriority = new SimpleIntegerProperty(Priority.DEFAULT_PRIORITY);
private IntegerProperty mNonAudioIdentifierCount = new SimpleIntegerProperty();
private StringProperty mAliasListName = new SimpleStringProperty();
private StringProperty mGroup = new SimpleStringProperty();
private StringProperty mIconName = new SimpleStringProperty();
private StringProperty mName = new SimpleStringProperty();
private ObservableList<AliasID> mAliasIDs = FXCollections.observableArrayList();
private ObservableList<AliasAction> mAliasActions = FXCollections.observableArrayList();
/**
* Constructs an instance and sets the specified name.
* @param name for the alias
*/
public Alias(String name)
{
mName = name;
mName.set(name);
//Bind the non-audio identifier count property to the size of a filtered list of alias identifiers
mNonAudioIdentifierCount.bind(Bindings.size(new FilteredList<>(mAliasIDs, aliasID -> {
return aliasID != null && !aliasID.isAudioIdentifier();
})));
}
/**
* Constructs an instance
*/
public Alias()
{
this(null);
}
/**
* Count of non-audio identifiers for this alias
*/
@JsonIgnore
public IntegerProperty nonAudioIdentifierCountProperty()
{
return mNonAudioIdentifierCount;
}
/**
* Audio playback priority
*/
@JsonIgnore
public IntegerProperty priorityProperty()
{
return mPriority;
}
/**
* Indicates if one or more of the identifiers for this alias overlap with identifiers from another alias
* within the same alias list.
*/
@JsonIgnore
public BooleanProperty overlapProperty()
{
return mOverlap;
}
/**
* Recordable property
*/
@JsonIgnore
public BooleanProperty recordableProperty()
{
return mRecordable;
}
/**
* Streamable property
*/
@JsonIgnore
public BooleanProperty streamableProperty()
{
return mStreamable;
}
/**
* Alias list name property
*/
@JsonIgnore
public StringProperty aliasListNameProperty()
{
return mAliasListName;
}
/**
* Group property
*/
@JsonIgnore
public StringProperty groupProperty()
{
return mGroup;
}
/**
* Alias name property
* @return
*/
@JsonIgnore
public StringProperty nameProperty()
{
return mName;
}
/**
* Alias color value property
*/
@JsonIgnore
public IntegerProperty colorProperty()
{
return mColor;
}
/**
* Icon name property
*/
@JsonIgnore
public StringProperty iconNameProperty()
{
return mIconName;
}
/**
* Alias identifiers list property
*/
@JsonIgnore
public ObservableList<AliasID> aliasIds()
{
return mAliasIDs;
}
/**
* Alias actions list property
*/
@JsonIgnore
public ObservableList<AliasAction> aliasActions()
{
return mAliasActions;
}
/**
* Uses name value for string representation
*/
public String toString()
{
return getName();
}
/**
* Alias name
*/
@JacksonXmlProperty(isAttribute = true, localName = "name")
public String getName()
{
return mName;
return mName.get();
}
public void setName(String name)
{
mName = name;
mName.set(name);
}
/**
* Alias list name for the alias list that this alias belongs to
*/
@JacksonXmlProperty(isAttribute = true, localName = "list")
public String getList()
public String getAliasListName()
{
return mList;
return mAliasListName.get();
}
public void setList(String list)
public void setAliasListName(String aliasListName)
{
mList = list;
mAliasListName.set(aliasListName);
}
@JsonIgnore
public boolean matchesAliasList(String aliasList)
{
boolean isEmptyArgument = aliasList == null || aliasList.isEmpty() || aliasList.contentEquals(AliasModel.NO_ALIAS_LIST);
boolean isEmptyThis = getAliasListName() == null || getAliasListName().isEmpty();
if(isEmptyArgument && isEmptyThis)
{
return true;
}
else if(!isEmptyArgument && !isEmptyThis && aliasList.contentEquals(getAliasListName()))
{
return true;
}
return false;
}
/**
* Indicates if this alias has a specified alias list name
*/
public boolean hasList()
{
return mList != null;
return mAliasListName.get() != null;
}
/**
* Grouping tag for this alias.
*/
@JacksonXmlProperty(isAttribute = true, localName = "group")
public String getGroup()
{
return mGroup;
return mGroup.get();
}
public void setGroup(String group)
{
mGroup = group;
mGroup.set(group);
}
/**
* Indicates if this alias has a grouping tag
*/
public boolean hasGroup()
{
return mGroup != null;
return mGroup.get() != null;
}
/**
* Color (RGBA) value to use for this alias
*/
@JacksonXmlProperty(isAttribute = true, localName = "color")
public int getColor()
{
return mColor;
return mColor.get();
}
@JsonIgnore
public String getColorHex()
{
return String.format("#%06X", (0xFFFFFF & mColor.get()));
}
public void setColor(int color)
{
mColor = color;
mColor.set(color);
}
/**
* Display color for this alias.
*/
@JsonIgnore
public Color getDisplayColor()
{
return new Color(getColor());
}
/**
* Icon name of the icon to use for this alias.
*/
@JacksonXmlProperty(isAttribute = true, localName = "iconName")
public String getIconName()
{
return mIconName;
return mIconName.get();
}
public void setIconName(String iconName)
{
mIconName = iconName;
mIconName.set(iconName);
}
/**
* List of alias identifiers for this alias.
*/
@JacksonXmlProperty(isAttribute = false, localName = "id")
public List<AliasID> getId()
public List<AliasID> getAliasIdentifiers()
{
return mAliasIDs;
}
public void setId(ArrayList<AliasID> id)
public void setAliasIdentifiers(List<AliasID> id)
{
mAliasIDs = id;
mAliasIDs.clear();
for(AliasID aliasID : id)
{
addAliasID(aliasID);
}
}
/**
* Adds an alias identifier to this alias and updates the recordable and streamable attributes.
*/
public void addAliasID(AliasID id)
{
mAliasIDs.add(id);
validate();
updateOverlapBinding();
}
/**
* Removes an alias identifier from this alias and updates the recordable and streamable attributes.
*/
public void removeAliasID(AliasID id)
{
mAliasIDs.remove(id);
if(id != null)
{
mAliasIDs.remove(id);
validate();
updateOverlapBinding();
}
}
/**
* List of alias actions associated with this alias.
*/
@JacksonXmlProperty(isAttribute = false, localName = "action")
public List<AliasAction> getAction()
public List<AliasAction> getAliasActions()
{
return mAliasActions;
}
public void setAction(List<AliasAction> actions)
public void setAliasActions(List<AliasAction> actions)
{
mAliasActions = actions;
mAliasActions.setAll(actions);
}
/**
* Adds the specified alias action to this alias
*/
public void addAliasAction(AliasAction action)
{
mAliasActions.add(action);
}
/**
* Removes the specified alias action from this alias
*/
public void removeAliasAction(AliasAction action)
{
mAliasActions.remove(action);
}
/**
* Indicates if this alias has any associated
* @return
*/
public boolean hasActions()
{
return !mAliasActions.isEmpty();
}
/**
* Updates the playback priority this alias
*/
private void updatePriority()
{
for(AliasID aliasID: mAliasIDs)
{
if(aliasID instanceof Priority)
{
mPriority.set(((Priority)aliasID).getPriority());
return;
}
}
mPriority.set(Priority.DEFAULT_PRIORITY);
}
private void updateOverlapBinding()
{
mOverlap.unbind();
BooleanBinding binding = new SimpleBooleanProperty(true).not();
for(AliasID aliasID: mAliasIDs)
{
binding = binding.or(aliasID.overlapProperty());
}
mOverlap.bind(binding);
}
/**
* Updates the recordable status for this alias
*/
private void updateRecordable()
{
for(AliasID aliasID: mAliasIDs)
{
if(aliasID instanceof Record)
{
mRecordable.set(true);
return;
}
}
mRecordable.set(false);
}
/**
* Updates the streamable status for this alias
*/
private void updateStreamable()
{
for(AliasID aliasID: mAliasIDs)
{
if(aliasID instanceof BroadcastChannel)
{
mStreamable.set(true);
return;
}
}
mStreamable.set(false);
}
/**
* Perform any validation/cleanup actions on this alias.
*/
public void validate()
{
updatePriority();
updateRecordable();
updateStreamable();
}
/**
* Returns the priority level of this alias, if defined, or the default priority
*/
@JsonIgnore
public int getCallPriority()
public int getPlaybackPriority()
{
for(AliasID id : mAliasIDs)
{
@@ -218,22 +526,23 @@ public class Alias
*/
public void setCallPriority(int priority)
{
if(priority == Priority.DO_NOT_MONITOR ||
(Priority.MIN_PRIORITY <= priority && priority <= Priority.MAX_PRIORITY))
{
for(AliasID id : mAliasIDs)
{
if(id.getType() == AliasIDType.PRIORITY)
{
((Priority)id).setPriority(priority);
return;
}
}
AliasID priorityID = null;
//If we don't find a priority id, create one
Priority p = new Priority();
p.setPriority(priority);
addAliasID(p);
for(AliasID aliasID: mAliasIDs)
{
if(aliasID instanceof Priority)
{
priorityID = aliasID;
}
}
removeAliasID(priorityID);
//Don't add a priority alias id if the priority is MAX_PRIORITY or DEFAULT_PRIORITY since the getCallPriority()
//will return that as the default value
if(priority == Priority.DO_NOT_MONITOR || (Priority.MIN_PRIORITY <= priority && priority < Priority.MAX_PRIORITY))
{
addAliasID(new Priority(priority));
}
}
@@ -243,51 +552,29 @@ public class Alias
@JsonIgnore
public boolean isRecordable()
{
for(AliasID id : getId())
{
if(id.getType() == AliasIDType.NON_RECORDABLE)
{
return false;
}
}
return true;
return mRecordable.get();
}
/**
* Sets or removes the non-recordable alias ID for this alias.
* Sets or removes the record alias ID for this alias.
*/
public void setRecordable(boolean recordable)
{
if(recordable)
AliasID recordID = null;
for(AliasID aliasID: mAliasIDs)
{
AliasID toRemove = null;
for(AliasID id : getId())
if(aliasID instanceof Record)
{
if(id.getType() == AliasIDType.NON_RECORDABLE)
{
toRemove = id;
break;
}
}
if(toRemove != null)
{
removeAliasID(toRemove);
recordID = aliasID;
}
}
else
{
for(AliasID id : getId())
{
if(id.getType() == AliasIDType.NON_RECORDABLE)
{
return;
}
}
addAliasID(new NonRecordable());
removeAliasID(recordID);
if(recordable)
{
addAliasID(new Record());
}
}
@@ -297,15 +584,7 @@ public class Alias
@JsonIgnore
public boolean isStreamable()
{
for(AliasID id : getId())
{
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
{
return true;
}
}
return false;
return mStreamable.get();
}
/**
@@ -316,7 +595,7 @@ public class Alias
{
Set<BroadcastChannel> broadcastChannels = new TreeSet<>();
for(AliasID id : getId())
for(AliasID id : getAliasIdentifiers())
{
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
{
@@ -337,15 +616,100 @@ public class Alias
return false;
}
for(AliasID id : getId())
for(AliasID id : getAliasIdentifiers())
{
if(id.getType() == AliasIDType.BROADCAST_CHANNEL &&
((BroadcastChannel)id).getChannelName().contentEquals(channel))
if(id instanceof BroadcastChannel)
{
return true;
BroadcastChannel broadcastChannel = (BroadcastChannel)id;
if(broadcastChannel.getChannelName() != null && broadcastChannel.getChannelName().contentEquals(channel))
{
return true;
}
}
}
return false;
}
/**
* Removes any broadcast channel(s) that match the argument
*/
public void removeBroadcastChannel(String channel)
{
if(channel == null || channel.isEmpty())
{
return;
}
List<AliasID> toRemove = new ArrayList<>();
for(AliasID aliasID: getAliasIdentifiers())
{
if(aliasID instanceof BroadcastChannel &&
((BroadcastChannel)aliasID).getChannelName().contentEquals(channel))
{
toRemove.add(aliasID);
}
}
for(AliasID aliasID: toRemove)
{
removeAliasID(aliasID);
}
}
/**
* Removes (clears) all broadcast channels from this alias
*/
public void removeAllBroadcastChannels()
{
List<AliasID> toRemove = new ArrayList<>();
for(AliasID aliasID: mAliasIDs)
{
if(aliasID instanceof BroadcastChannel)
{
toRemove.add(aliasID);
}
}
for(AliasID aliasID: toRemove)
{
removeAliasID(aliasID);
}
}
/**
* Removes all non audio identifiers to prepare for replacing them from an editor.
*/
public void removeNonAudioIdentifiers()
{
Iterator<AliasID> it = mAliasIDs.iterator();
while(it.hasNext())
{
if(!it.next().isAudioIdentifier())
{
it.remove();
}
}
}
/**
* Removes all alias actions from this alias
*/
public void removeAllActions()
{
mAliasActions.clear();
}
/**
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
*/
public static Callback<Alias,Observable[]> extractor()
{
return (Alias a) -> new Observable[] {a.recordableProperty(), a.streamableProperty(), a.colorProperty(),
a.aliasListNameProperty(), a.groupProperty(), a.iconNameProperty(), a.nameProperty(), a.aliasIds(),
a.aliasActions(), a.nonAudioIdentifierCountProperty(), a.overlapProperty()};
}
}

View File

@@ -1,356 +0,0 @@
package io.github.dsheirer.alias;
import com.jidesoft.swing.JideSplitPane;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.icon.IconManager;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class AliasController extends JPanel
implements ActionListener, ListSelectionListener
{
private static final long serialVersionUID = 1L;
private AliasModel mAliasModel;
private JTable mAliasTable;
private TableFilterHeader mTableFilterHeader;
private AliasEditor mAliasEditor;
private MultipleAliasEditor mMultipleAliasEditor;
private JideSplitPane mSplitPane;
private static final String NEW_ALIAS = "New";
private static final String COPY_ALIAS = "Copy";
private static final String DELETE_ALIAS = "Delete";
private JButton mNewButton = new JButton(NEW_ALIAS);
private JButton mCopyButton = new JButton(COPY_ALIAS);
private JButton mDeleteButton = new JButton(DELETE_ALIAS);
private IconCellRenderer mIconCellRenderer;
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mAliasEditor = new AliasEditor(mAliasModel, broadcastModel, iconManager);
mMultipleAliasEditor = new MultipleAliasEditor(mAliasModel, broadcastModel, iconManager);
mIconCellRenderer = new IconCellRenderer(iconManager);
init();
mAliasModel.addListener(mAliasEditor);
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0",
"[grow,fill]",
"[grow,fill]"));
//System Configuration View and Editor
mAliasTable = new JTable(mAliasModel);
mAliasTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
mAliasTable.getSelectionModel().addListSelectionListener(this);
mAliasTable.setAutoCreateRowSorter(true);
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_COLOR)
.setCellRenderer(new ColorCellRenderer());
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_ICON)
.setCellRenderer(mIconCellRenderer);
mTableFilterHeader = new TableFilterHeader(mAliasTable, AutoChoices.ENABLED);
mTableFilterHeader.setFilterOnUpdates(true);
JScrollPane tableScroller = new JScrollPane(mAliasTable);
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]"));
mNewButton.addActionListener(this);
mNewButton.setToolTipText("Adds a new alias");
buttonsPanel.add(mNewButton);
mCopyButton.addActionListener(this);
mCopyButton.setEnabled(false);
mCopyButton.setToolTipText("Creates a copy of the currently selected alias and adds it");
buttonsPanel.add(mCopyButton);
mDeleteButton.addActionListener(this);
mDeleteButton.setEnabled(false);
mDeleteButton.setToolTipText("Deletes the currently selected alias");
buttonsPanel.add(mDeleteButton);
JPanel listAndButtonsPanel = new JPanel();
listAndButtonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill][]"));
listAndButtonsPanel.add(tableScroller, "wrap");
listAndButtonsPanel.add(buttonsPanel);
mSplitPane = new JideSplitPane(JideSplitPane.HORIZONTAL_SPLIT);
mSplitPane.setDividerSize(5);
mSplitPane.setShowGripper(true);
mSplitPane.add(listAndButtonsPanel);
mSplitPane.add(mAliasEditor);
add(mSplitPane);
}
/**
* Sets the editor argument as the currently visible alias editor
*/
private void setEditor(Editor<?> editor)
{
if(mSplitPane.getComponentCount() == 3)
{
Component component = mSplitPane.getComponent(2);
if(component instanceof Editor<?> && component != editor)
{
//Get current divider location so that we can reapply it after
//changing out the editors, so that the interface doesn't move
int location = mSplitPane.getDividerLocation(0);
((Editor<?>) component).setItem(null);
mSplitPane.remove(component);
editor.setPreferredSize(new Dimension(100, 100));
mSplitPane.add(editor);
mSplitPane.validate();
mSplitPane.setDividerLocation(0, location);
mSplitPane.repaint();
}
}
}
private Alias getAlias(int selectedRow)
{
if(selectedRow >= 0)
{
int index = mAliasTable.convertRowIndexToModel(selectedRow);
return mAliasModel.getAliasAtIndex(index);
}
return null;
}
@Override
public void valueChanged(ListSelectionEvent event)
{
//Limits event firing to only when selection is complete
if(!event.getValueIsAdjusting())
{
int[] selectedRows = mAliasTable.getSelectedRows();
if(selectedRows.length == 0)
{
mAliasEditor.setItem(null);
mCopyButton.setEnabled(false);
mDeleteButton.setEnabled(false);
}
else if(selectedRows.length == 1)
{
setEditor(mAliasEditor);
Alias selectedAlias = getAlias(selectedRows[0]);
mAliasEditor.setItem(selectedAlias);
if(selectedAlias != null)
{
mCopyButton.setEnabled(true);
mDeleteButton.setEnabled(true);
}
else
{
mCopyButton.setEnabled(false);
mDeleteButton.setEnabled(false);
}
}
else
{
setEditor(mMultipleAliasEditor);
mCopyButton.setEnabled(true);
mDeleteButton.setEnabled(true);
List<Alias> selectedAliases = new ArrayList<Alias>();
for(int selectedRow : selectedRows)
{
Alias alias = getAlias(selectedRow);
selectedAliases.add(alias);
}
mMultipleAliasEditor.setItem(selectedAliases);
}
}
}
/**
* Adds the alias to the alias table/model and scrolls the view it
*/
private void addAlias(Alias alias)
{
//HACK: when inserting a row to the model, the JTable gets
//notified and attempts to tell the coderazzi table filter
//adaptive choices filter to refresh before the table filter is
//notified of the row additions, causing an index out of bounds
//exception. We turn off adaptive choices temporarily, add the
//channel, and turn on adaptive choices again.
mTableFilterHeader.setAdaptiveChoices(false);
int index = mAliasModel.addAlias(alias);
mTableFilterHeader.setAdaptiveChoices(true);
if(index >= 0)
{
int translatedIndex = mAliasTable.convertRowIndexToView(index);
mAliasTable.setRowSelectionInterval(translatedIndex, translatedIndex);
mAliasTable.scrollRectToVisible(
new Rectangle(mAliasTable.getCellRect(translatedIndex, 0, true)));
}
}
private List<Alias> getSelectedAliases()
{
List<Alias> selected = new ArrayList<>();
int[] rows = mAliasTable.getSelectedRows();
for(int row : rows)
{
if(row >= 0)
{
Alias alias = mAliasModel.getAliasAtIndex(mAliasTable.convertRowIndexToModel(row));
if(alias != null)
{
selected.add(alias);
}
}
}
return selected;
}
/**
* Responds to New, Copy and Delete Channel button invocations
*/
@Override
public void actionPerformed(ActionEvent event)
{
switch(event.getActionCommand())
{
case NEW_ALIAS:
addAlias(new Alias("New Alias"));
break;
case COPY_ALIAS:
for(Alias alias : getSelectedAliases())
{
addAlias(AliasFactory.copyOf(alias));
}
break;
case DELETE_ALIAS:
List<Alias> toDelete = getSelectedAliases();
if(toDelete != null && !toDelete.isEmpty())
{
String title = toDelete.size() == 1 ? "Delete Alias?" : "Delete Aliases?";
String prompt = toDelete.size() == 1 ? "Do you want to delete this alias?" :
"Do you want to delete these " + toDelete.size() + " aliases?";
int choice = JOptionPane.showConfirmDialog(AliasController.this,
prompt, title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if(choice == JOptionPane.YES_OPTION)
{
for(Alias alias : toDelete)
{
mAliasModel.removeAlias(alias);
}
}
}
break;
default:
break;
}
}
/**
* Colorizes the cell based on the cell's integer value
*/
public class ColorCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
label.setBackground(new Color((int) value));
label.setText("");
return label;
}
}
/**
* Displays cell's icon and name
*/
public class IconCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
private IconManager mIconManager;
public IconCellRenderer(IconManager iconManager)
{
mIconManager = iconManager;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
ImageIcon icon = mIconManager.getIcon(label.getText(), 12);
if(icon != null)
{
label.setIcon(icon);
}
return label;
}
}
}

View File

@@ -1,158 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias;
import com.jidesoft.swing.JideTabbedPane;
import io.github.dsheirer.alias.action.AliasActionEditor;
import io.github.dsheirer.alias.id.AliasIdentifierEditor;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.icon.IconManager;
import io.github.dsheirer.sample.Listener;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AliasEditor extends Editor<Alias>
implements ActionListener, Listener<AliasEvent>
{
private static final long serialVersionUID = 1L;
private static final String DEFAULT_NAME = "select an alias";
private AliasModel mAliasModel;
private JLabel mAliasLabel;
private AliasNameEditor mAliasNameEditor;
private AliasIdentifierEditor mAliasIdentifierEditor;
private AliasActionEditor mAliasActionEditor;
public AliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager )
{
mAliasModel = aliasModel;
mAliasNameEditor = new AliasNameEditor( mAliasModel, iconManager );
mAliasIdentifierEditor = new AliasIdentifierEditor( aliasModel, broadcastModel );
mAliasActionEditor = new AliasActionEditor( aliasModel );
mAliasModel.addListener( this );
init();
}
@Override
public void setItem( Alias alias )
{
super.setItem( alias );
if( hasItem() )
{
mAliasLabel.setText( getItem().getName() );
}
else
{
mAliasLabel.setText( DEFAULT_NAME );
}
mAliasNameEditor.setItem( alias );
mAliasIdentifierEditor.setItem( alias );
mAliasActionEditor.setItem( alias );
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[grow,fill][grow,fill]",
"[][][][][][grow,fill]" ) );
add( new JLabel( "Alias:" ), "align right" );
mAliasLabel = new JLabel( DEFAULT_NAME );
add( mAliasLabel, "align left" );
add( new JSeparator( JSeparator.HORIZONTAL ), "span,growx,push" );
JideTabbedPane tabs = new JideTabbedPane();
tabs.setFont( this.getFont() );
tabs.setForeground( Color.BLACK );
tabs.addTab( "Alias", mAliasNameEditor );
tabs.addTab( "Audio / Identifier", mAliasIdentifierEditor );
tabs.addTab( "Action", mAliasActionEditor );
add( tabs, "span,grow" );
//Playlist management buttons
JButton btnSave = new JButton( "Save" );
btnSave.setToolTipText( "Save alias changes to the playlist" );
btnSave.addActionListener( AliasEditor.this );
add( btnSave );
JButton btnReset = new JButton( "Reset" );
btnReset.setToolTipText( "Reset alias changes since last save" );
btnReset.addActionListener( AliasEditor.this );
add( btnReset, "wrap" );
}
@Override
public void receive( AliasEvent event )
{
//If this is the currently displayed alias, reload it
if( hasItem() && getItem() == event.getAlias() )
{
switch( event.getEvent() )
{
case CHANGE:
//Alias changed - reset the editor with changed alias
setItem( event.getAlias() );
break;
case DELETE:
setItem( null );
break;
default:
break;
}
}
}
@Override
public void actionPerformed( ActionEvent e )
{
if( hasItem() )
{
String command = e.getActionCommand();
if( command.contentEquals( "Save" ) )
{
save();
}
else if( command.contentEquals( "Reset" ) )
{
reset();
}
}
}
@Override
public void save()
{
mAliasNameEditor.save();
mAliasIdentifierEditor.save();
mAliasActionEditor.save();
}
}

View File

@@ -1,55 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias;
public class AliasEvent
{
private Alias mAlias;
private Event mEvent;
/**
* AliasEvent - event describing any changes to an alias
* @param alias - alias that changed
* @param event - change event
*/
public AliasEvent( Alias alias, Event event )
{
mAlias = alias;
mEvent = event;
}
public Alias getAlias()
{
return mAlias;
}
public Event getEvent()
{
return mEvent;
}
/**
* Channel events to describe the specific event
*/
public enum Event
{
ADD,
CHANGE,
DELETE;
}
}

View File

@@ -1,304 +1,249 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias;
import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.action.AliasActionType;
import io.github.dsheirer.alias.action.beep.BeepAction;
import io.github.dsheirer.alias.action.beep.BeepActionEditor;
import io.github.dsheirer.alias.action.clip.ClipAction;
import io.github.dsheirer.alias.action.clip.ClipActionEditor;
import io.github.dsheirer.alias.action.script.ScriptAction;
import io.github.dsheirer.alias.action.script.ScriptActionEditor;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannelEditor;
import io.github.dsheirer.alias.id.esn.ESNEditor;
import io.github.dsheirer.alias.id.dcs.Dcs;
import io.github.dsheirer.alias.id.esn.Esn;
import io.github.dsheirer.alias.id.fleetsync.FleetsyncID;
import io.github.dsheirer.alias.id.fleetsync.FleetsyncIDEditor;
import io.github.dsheirer.alias.id.legacy.mobileID.Min;
import io.github.dsheirer.alias.id.legacy.siteID.SiteID;
import io.github.dsheirer.alias.id.lojack.LoJackFunctionAndID;
import io.github.dsheirer.alias.id.lojack.LoJackIDEditor;
import io.github.dsheirer.alias.id.mdc.MDC1200ID;
import io.github.dsheirer.alias.id.mdc.MDC1200IDEditor;
import io.github.dsheirer.alias.id.mobileID.MINEditor;
import io.github.dsheirer.alias.id.mobileID.Min;
import io.github.dsheirer.alias.id.mpt1327.MPT1327ID;
import io.github.dsheirer.alias.id.mpt1327.MPT1327IDEditor;
import io.github.dsheirer.alias.id.nonrecordable.NonRecordable;
import io.github.dsheirer.alias.id.nonrecordable.NonRecordableEditor;
import io.github.dsheirer.alias.id.priority.Priority;
import io.github.dsheirer.alias.id.priority.PriorityEditor;
import io.github.dsheirer.alias.id.siteID.SiteID;
import io.github.dsheirer.alias.id.siteID.SiteIDEditor;
import io.github.dsheirer.alias.id.status.StatusID;
import io.github.dsheirer.alias.id.status.StatusIDEditor;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupID;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupIDEditor;
import io.github.dsheirer.alias.id.uniqueID.UniqueID;
import io.github.dsheirer.alias.id.uniqueID.UniqueIDEditor;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EmptyEditor;
import io.github.dsheirer.alias.id.radio.P25FullyQualifiedRadio;
import io.github.dsheirer.alias.id.radio.Radio;
import io.github.dsheirer.alias.id.radio.RadioRange;
import io.github.dsheirer.alias.id.record.Record;
import io.github.dsheirer.alias.id.status.UnitStatusID;
import io.github.dsheirer.alias.id.status.UserStatusID;
import io.github.dsheirer.alias.id.talkgroup.P25FullyQualifiedTalkgroup;
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
import io.github.dsheirer.alias.id.tone.TonesID;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AliasFactory
{
public static AliasID copyOf( AliasID id )
{
switch( id.getType() )
{
case BROADCAST_CHANNEL:
BroadcastChannel originalBroadcast = (BroadcastChannel)id;
BroadcastChannel copyBroadcast = new BroadcastChannel();
copyBroadcast.setChannelName(originalBroadcast.getChannelName());
return copyBroadcast;
case ESN:
Esn originalESN = (Esn)id;
Esn copyESN = new Esn();
copyESN.setEsn( originalESN.getEsn() );
return copyESN;
case FLEETSYNC:
FleetsyncID originalFleetsyncID = (FleetsyncID)id;
FleetsyncID copyFleetsyncID = new FleetsyncID();
copyFleetsyncID.setIdent( originalFleetsyncID.getIdent() );
return copyFleetsyncID;
case LTR_NET_UID:
UniqueID originalUniqueID = (UniqueID)id;
UniqueID copyUniqueID = new UniqueID();
copyUniqueID.setUid( originalUniqueID.getUid() );
return copyUniqueID;
case LOJACK:
LoJackFunctionAndID originalLoJackFunctionAndID = (LoJackFunctionAndID)id;
LoJackFunctionAndID copyLoJackFunctionAndID = new LoJackFunctionAndID();
copyLoJackFunctionAndID.setFunction( originalLoJackFunctionAndID.getFunction() );
copyLoJackFunctionAndID.setID( originalLoJackFunctionAndID.getID() );
return copyLoJackFunctionAndID;
case MDC1200:
MDC1200ID originalMDC1200ID = (MDC1200ID)id;
MDC1200ID copyMDC1200ID = new MDC1200ID();
copyMDC1200ID.setIdent( originalMDC1200ID.getIdent() );
return copyMDC1200ID;
case MIN:
Min originalMin = (Min)id;
Min copyMin = new Min();
copyMin.setMin( originalMin.getMin() );
return copyMin;
case MPT1327:
MPT1327ID originalMPT1327ID = (MPT1327ID)id;
MPT1327ID copyMPT1327ID = new MPT1327ID();
copyMPT1327ID.setIdent( originalMPT1327ID.getIdent() );
return copyMPT1327ID;
case NON_RECORDABLE:
return new NonRecordable();
case PRIORITY:
Priority originalPriority = (Priority)id;
Priority copyPriority = new Priority();
copyPriority.setPriority( originalPriority.getPriority() );
return copyPriority;
case SITE:
SiteID originalSiteID = (SiteID)id;
SiteID copySiteID = new SiteID();
copySiteID.setSite( originalSiteID.getSite() );
return copySiteID;
case TALKGROUP:
TalkgroupID originalTalkgroupID = (TalkgroupID)id;
TalkgroupID copyTalkgroupID = new TalkgroupID();
copyTalkgroupID.setTalkgroup( originalTalkgroupID.getTalkgroup() );
return copyTalkgroupID;
case STATUS:
StatusID originalStatusID = (StatusID)id;
StatusID copyStatusID = new StatusID();
copyStatusID.setStatus( originalStatusID.getStatus() );
return copyStatusID;
default:
}
private static final Logger mLog = LoggerFactory.getLogger(AliasFactory.class);
return null;
}
public static AliasAction copyOf( AliasAction action )
{
if( action instanceof BeepAction )
{
return new BeepAction();
}
else if( action instanceof ClipAction)
{
ClipAction originalClip = (ClipAction)action;
ClipAction copyClip = new ClipAction();
copyClip.setInterval( originalClip.getInterval() );
copyClip.setPath( originalClip.getPath() );
copyClip.setPeriod( originalClip.getPeriod() );
return copyClip;
}
else if( action instanceof ScriptAction )
{
ScriptAction originalScript = (ScriptAction)action;
ScriptAction copyScript = new ScriptAction();
copyScript.setInterval( originalScript.getInterval() );
copyScript.setPeriod( originalScript.getPeriod() );
copyScript.setScript( originalScript.getScript() );
return copyScript;
}
return null;
}
public static Alias copyOf( Alias original )
{
Alias copy = new Alias( original.getName() );
copy.setList( original.getList() );
copy.setGroup( original.getGroup() );
copy.setColor( original.getColor() );
copy.setIconName( original.getIconName() );
for( AliasID id: original.getId() )
{
AliasID copyID = copyOf( id );
if( copyID != null )
{
copy.addAliasID( copyID );
}
}
public static AliasID copyOf(AliasID id)
{
switch(id.getType())
{
case BROADCAST_CHANNEL:
BroadcastChannel originalBroadcast = (BroadcastChannel)id;
BroadcastChannel copyBroadcast = new BroadcastChannel();
copyBroadcast.setChannelName(originalBroadcast.getChannelName());
return copyBroadcast;
case DCS:
Dcs originalDcs = (Dcs)id;
Dcs copyDcs = new Dcs();
copyDcs.setDCSCode(originalDcs.getDCSCode());
return copyDcs;
case ESN:
Esn originalESN = (Esn)id;
Esn copyESN = new Esn();
copyESN.setEsn(originalESN.getEsn());
return copyESN;
case LOJACK:
LoJackFunctionAndID originalLoJackFunctionAndID = (LoJackFunctionAndID)id;
LoJackFunctionAndID copyLoJackFunctionAndID = new LoJackFunctionAndID();
copyLoJackFunctionAndID.setFunction(originalLoJackFunctionAndID.getFunction());
copyLoJackFunctionAndID.setID(originalLoJackFunctionAndID.getID());
return copyLoJackFunctionAndID;
case MIN:
Min originalMin = (Min)id;
Min copyMin = new Min();
copyMin.setMin(originalMin.getMin());
return copyMin;
case P25_FULLY_QUALIFIED_RADIO_ID:
P25FullyQualifiedRadio originalP25 = (P25FullyQualifiedRadio) id;
P25FullyQualifiedRadio copyP25 = new P25FullyQualifiedRadio(originalP25.getWacn(),
originalP25.getSystem(), originalP25.getValue());
copyP25.setOverlap(originalP25.overlapProperty().get());
return copyP25;
case P25_FULLY_QUALIFIED_TALKGROUP:
P25FullyQualifiedTalkgroup originalFqt = (P25FullyQualifiedTalkgroup) id;
P25FullyQualifiedTalkgroup copyFqt = new P25FullyQualifiedTalkgroup(originalFqt.getWacn(),
originalFqt.getSystem(), originalFqt.getValue());
copyFqt.setOverlap(originalFqt.overlapProperty().get());
return copyFqt;
case PRIORITY:
Priority originalPriority = (Priority)id;
Priority copyPriority = new Priority();
copyPriority.setPriority(originalPriority.getPriority());
return copyPriority;
case RADIO_ID:
Radio originalRadio = (Radio)id;
Radio copyRadio = new Radio(originalRadio.getProtocol(), originalRadio.getValue());
copyRadio.setOverlap(originalRadio.overlapProperty().get());
return copyRadio;
case RADIO_ID_RANGE:
RadioRange originalRadioRange = (RadioRange)id;
RadioRange copyRadioRange = new RadioRange(originalRadioRange.getProtocol(), originalRadioRange.getMinRadio(),
originalRadioRange.getMaxRadio());
copyRadioRange.setOverlap(originalRadioRange.overlapProperty().get());
return copyRadioRange;
case RECORD:
return new Record();
case SITE:
SiteID originalSiteID = (SiteID)id;
SiteID copySiteID = new SiteID();
copySiteID.setSite(originalSiteID.getSite());
return copySiteID;
case STATUS:
UserStatusID originalUserStatusID = (UserStatusID)id;
UserStatusID copyUserStatusID = new UserStatusID();
copyUserStatusID.setStatus(originalUserStatusID.getStatus());
copyUserStatusID.setOverlap(originalUserStatusID.overlapProperty().get());
return copyUserStatusID;
case TALKGROUP:
Talkgroup originalTalkgroup = (Talkgroup)id;
Talkgroup copyTalkgroup = new Talkgroup(originalTalkgroup.getProtocol(), originalTalkgroup.getValue());
copyTalkgroup.setOverlap(originalTalkgroup.overlapProperty().get());
return copyTalkgroup;
case TALKGROUP_RANGE:
TalkgroupRange originalRange = (TalkgroupRange)id;
TalkgroupRange copyRange = new TalkgroupRange(originalRange.getProtocol(), originalRange.getMinTalkgroup(),
originalRange.getMaxTalkgroup());
copyRange.setOverlap(originalRange.overlapProperty().get());
return copyRange;
case TONES:
TonesID originalTones = (TonesID)id;
TonesID copyTones = new TonesID();
copyTones.setToneSequence(originalTones.getToneSequence().copyOf());
return copyTones;
case UNIT_STATUS:
UnitStatusID originalUnitStatus = (UnitStatusID)id;
UnitStatusID copyUnitStatusID = new UnitStatusID();
copyUnitStatusID.setStatus(originalUnitStatus.getStatus());
copyUnitStatusID.setOverlap(originalUnitStatus.overlapProperty().get());
return copyUnitStatusID;
for( AliasAction action: original.getAction() )
{
AliasAction copyAction = copyOf( action );
if( copyAction != null )
{
copy.addAliasAction( copyAction );
}
}
return copy;
}
//Legacy identifiers ... not supported
case FLEETSYNC:
case LEGACY_TALKGROUP:
case LTR_NET_UID:
case MDC1200:
case MPT1327:
case NON_RECORDABLE:
return null;
default:
mLog.warn("Unrecognized Alias ID Type [" + id.getType() + "] cannot make copy of instance");
break;
}
public static Editor<AliasID> getEditor( AliasID aliasID, BroadcastModel broadcastModel )
{
if( aliasID != null )
{
switch( aliasID.getType() )
{
case BROADCAST_CHANNEL:
return new BroadcastChannelEditor(aliasID, broadcastModel);
case ESN:
return new ESNEditor( aliasID );
case FLEETSYNC:
return new FleetsyncIDEditor( aliasID );
case LTR_NET_UID:
return new UniqueIDEditor( aliasID );
case LOJACK:
return new LoJackIDEditor( aliasID );
case MDC1200:
return new MDC1200IDEditor( aliasID );
case MIN:
return new MINEditor( aliasID );
case MPT1327:
return new MPT1327IDEditor( aliasID );
case NON_RECORDABLE:
return new NonRecordableEditor( aliasID );
case PRIORITY:
return new PriorityEditor( aliasID );
case SITE:
return new SiteIDEditor( aliasID );
case STATUS:
return new StatusIDEditor( aliasID );
case TALKGROUP:
return new TalkgroupIDEditor( aliasID );
default:
break;
}
}
return new EmptyEditor<AliasID>();
}
public static Editor<AliasAction> getEditor( AliasAction aliasAction )
{
if( aliasAction != null )
{
switch( aliasAction.getType() )
{
case BEEP:
return new BeepActionEditor( aliasAction );
case CLIP:
return new ClipActionEditor( aliasAction );
case SCRIPT:
return new ScriptActionEditor( aliasAction );
default:
break;
}
}
return new EmptyEditor<AliasAction>();
}
public static AliasID getAliasID( AliasIDType type )
{
switch( type )
{
case BROADCAST_CHANNEL:
return new BroadcastChannel();
case ESN:
return new Esn();
case FLEETSYNC:
return new FleetsyncID();
case LTR_NET_UID:
return new UniqueID();
case LOJACK:
return new LoJackFunctionAndID();
case MDC1200:
return new MDC1200ID();
case MIN:
return new Min();
case MPT1327:
return new MPT1327ID();
case NON_RECORDABLE:
return new NonRecordable();
case PRIORITY:
return new Priority();
case SITE:
return new SiteID();
case STATUS:
return new StatusID();
case TALKGROUP:
return new TalkgroupID();
default:
throw new IllegalArgumentException( "Unrecognized Alias ID type: " + type );
}
}
public static AliasAction getAliasAction( AliasActionType type )
{
switch( type )
{
case BEEP:
return new BeepAction();
case CLIP:
return new ClipAction();
case SCRIPT:
return new ScriptAction();
default:
throw new IllegalArgumentException( "Unrecognized Alias Action type: " + type );
}
}
return null;
}
public static AliasAction copyOf(AliasAction action)
{
if(action instanceof BeepAction)
{
BeepAction original = (BeepAction)action;
BeepAction copyBeep = new BeepAction();
copyBeep.setInterval(original.getInterval());
copyBeep.setPeriod(original.getPeriod());
return copyBeep;
}
else if(action instanceof ClipAction)
{
ClipAction originalClip = (ClipAction)action;
ClipAction copyClip = new ClipAction();
copyClip.setInterval(originalClip.getInterval());
copyClip.setPath(originalClip.getPath());
copyClip.setPeriod(originalClip.getPeriod());
return copyClip;
}
else if(action instanceof ScriptAction)
{
ScriptAction originalScript = (ScriptAction)action;
ScriptAction copyScript = new ScriptAction();
copyScript.setInterval(originalScript.getInterval());
copyScript.setPeriod(originalScript.getPeriod());
copyScript.setScript(originalScript.getScript());
return copyScript;
}
return null;
}
public static Alias shallowCopyOf(Alias original)
{
Alias copy = new Alias(original.getName());
copy.setAliasListName(original.getAliasListName());
copy.setGroup(original.getGroup());
copy.setColor(original.getColor());
copy.setIconName(original.getIconName());
copy.setRecordable(original.isRecordable());
return copy;
}
public static List<AliasID> copyAliasIDs(Alias original)
{
List<AliasID> aliasIDS = new ArrayList<>();
for(AliasID id : original.getAliasIdentifiers())
{
aliasIDS.add(copyOf(id));
}
return aliasIDS;
}
public static List<AliasAction> copyAliasActions(Alias original)
{
List<AliasAction> actions = new ArrayList<>();
for(AliasAction aliasAction: original.getAliasActions())
{
actions.add(copyOf(aliasAction));
}
return actions;
}
public static Alias copyOf(Alias original)
{
Alias copy = shallowCopyOf(original);
List<AliasID> aliasIDS = copyAliasIDs(original);
for(AliasID aliasID: aliasIDS)
{
copy.addAliasID(aliasID);
}
List<AliasAction> actions = copyAliasActions(original);
for(AliasAction action: actions)
{
copy.addAliasAction(action);
}
return copy;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +1,66 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import javax.swing.table.AbstractTableModel;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Alias Model
* Alias Model contains all aliases and is responsible for creation and management of alias lists. Alias lists are a
* set of aliases that all share a common alias list name and can be attached to a decoding channel for aliasing
* identifiers produced by channel decoder(s).
*/
public class AliasModel extends AbstractTableModel
public class AliasModel
{
private static final long serialVersionUID = 1L;
public static final int COLUMN_LIST = 0;
public static final int COLUMN_GROUP = 1;
public static final int COLUMN_NAME = 2;
public static final int COLUMN_ICON = 3;
public static final int COLUMN_COLOR = 4;
private List<Alias> mAliases = new CopyOnWriteArrayList<>();
private Broadcaster<AliasEvent> mAliasEventBroadcaster = new Broadcaster<>();
private final static Logger mLog = LoggerFactory.getLogger(AliasModel.class);
public static final String NO_ALIAS_LIST = "(No Alias List)";
private ObservableList<Alias> mAliases = FXCollections.observableArrayList(Alias.extractor());
private ObservableList<String> mAliasListNames = FXCollections.observableArrayList();
private Map<String,AliasList> mAliasListMap = new HashMap<>();
public AliasModel()
{
//Register a listener to detect alias changes and broadcast change events to cause playlist save requests
mAliases.addListener(new AliasListChangeListener());
}
public ObservableList<Alias> aliasList()
{
return mAliases;
}
public ObservableList<String> aliasListNames()
{
return mAliasListNames;
}
/**
@@ -58,41 +71,82 @@ public class AliasModel extends AbstractTableModel
return Collections.unmodifiableList(mAliases);
}
public Alias getAliasAtIndex(int row)
/**
* Removes all aliases from the list and broadcasts the alias delete event for each
*/
public void clear()
{
if(mAliases.size() >= row)
List<Alias> aliasToRemove = new ArrayList<>(mAliases);
for(Alias alias: aliasToRemove)
{
return mAliases.get(row);
removeAlias(alias);
}
mAliasListNames.clear();
}
/**
* Returns an optional alias list associated with the identifier collection
*
* @return alias list or null
*/
public AliasList getAliasList(IdentifierCollection identifierCollection)
{
if(identifierCollection != null)
{
return getAliasList(identifierCollection.getAliasListConfiguration());
}
return null;
}
/**
* Retrieves an alias list specified by the alias list configuration identifier
*
* @param configurationIdentifier containing the name of an alias list
* @return alias list or null.
*/
public AliasList getAliasList(AliasListConfigurationIdentifier configurationIdentifier)
{
if(configurationIdentifier != null && configurationIdentifier.isValid())
{
return getAliasList(configurationIdentifier.getValue());
}
return null;
}
/**
* Creates a new alias list containing all aliases that match the alias name, or returns a previously created and
* cached alias list. Returned alias list is automatically registered as a listener to this model so that any
* updates to the list by the user will automatically be reflected in constructed alias lists.
*/
public AliasList getAliasList(String name)
{
if(name != null && mAliasListMap.containsKey(name))
if(name == null || name.isEmpty())
{
return mAliasListMap.get(name);
return new AliasList(name);
}
AliasList mapValue = mAliasListMap.get(name);
if (mapValue != null)
{
return mapValue;
}
AliasList aliasList = new AliasList(name);
if(name != null)
for(Alias alias : mAliases)
{
for(Alias alias : mAliases)
if(alias.hasList() && alias.getAliasListName().equalsIgnoreCase(name))
{
if(alias.hasList() && alias.getList().equalsIgnoreCase(name))
{
aliasList.addAlias(alias);
}
aliasList.addAlias(alias);
}
mAliasListMap.put(name, aliasList);
//Register the new alias list to receive updates from this model
addListener(aliasList);
}
mAliasListMap.put(name, aliasList);
return aliasList;
}
@@ -101,19 +155,7 @@ public class AliasModel extends AbstractTableModel
*/
public List<String> getListNames()
{
List<String> listNames = new ArrayList<>();
for(Alias alias : mAliases)
{
if(alias.hasList() && !listNames.contains(alias.getList()))
{
listNames.add(alias.getList());
}
}
Collections.sort(listNames);
return listNames;
return mAliasListNames;
}
/**
@@ -136,214 +178,209 @@ public class AliasModel extends AbstractTableModel
return groupNames;
}
/**
* Returns a list of alias group names for all aliases that have a matching
* list name value
*/
public List<String> getGroupNames(String listName)
{
List<String> groupNames = new ArrayList<>();
if(listName != null)
{
for(Alias alias : mAliases)
{
if(alias.hasList() &&
alias.hasGroup() &&
listName.equals(alias.getList()) &&
!groupNames.contains(alias.getGroup()))
{
groupNames.add(alias.getGroup());
}
}
}
Collections.sort(groupNames);
return groupNames;
}
/**
* Bulk loading of aliases
*/
public void addAliases(List<Alias> aliases)
{
for(Alias alias : aliases)
{
addAlias(alias);
}
removeAliases(aliases);
mAliases.addAll(aliases);
}
/**
* Adds the alias to the model
*/
public int addAlias(Alias alias)
public void addAlias(Alias alias)
{
if(alias != null)
if(mAliases.contains(alias))
{
mAliases.add(alias);
int index = mAliases.size() - 1;
fireTableRowsInserted(index, index);
broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
return index;
removeAlias(alias);
}
return -1;
mAliases.add(alias);
}
private boolean hasAliasList(String aliasListName)
{
return aliasListName != null && mAliasListMap.containsKey(aliasListName);
}
public void addAliasList(String aliasListName)
{
if(aliasListName != null && !aliasListName.isEmpty())
{
if(!mAliasListNames.contains(aliasListName))
{
mAliasListNames.add(aliasListName);
}
}
else if(!mAliasListNames.contains(NO_ALIAS_LIST))
{
//This list allows users to view unassigned aliases so that they can move them to a valid alias list, but
// it is not assignable to a channel
mAliasListNames.add(NO_ALIAS_LIST);
}
}
/**
* Removes the channel from the model and broadcasts a channel remove event
* Removes the alias from this model and an alias list (if one exists)
*/
public void removeAlias(Alias alias)
{
if(alias != null)
{
int index = mAliases.indexOf(alias);
mAliases.remove(alias);
fireTableRowsDeleted(index, index);
broadcast(new AliasEvent(alias, AliasEvent.Event.DELETE));
if(hasAliasList(alias.getAliasListName()))
{
getAliasList(alias.getAliasListName()).removeAlias(alias);
}
}
}
/**
* Renames any broadcast channels that have the previous name.
*
* @param previousName to rename
* @param newName to assign to the broadcast channel
* Removes the list of aliases from this model and any alias lists that might contain each alias.
* @param aliases
*/
public void renameBroadcastChannel(String previousName, String newName)
public void removeAliases(List<Alias> aliases)
{
if(previousName == null || previousName.isEmpty() || newName == null || newName.isEmpty())
if(aliases != null && !aliases.isEmpty())
{
mAliases.removeAll(aliases);
for(Alias alias: aliases)
{
if(hasAliasList(alias.getAliasListName()))
{
getAliasList(alias.getAliasListName()).removeAlias(alias);
}
}
}
}
/**
* Retrieves all aliases that match the alias list and have at least one alias ID of the specified type
* @param aliasListName to search
* @param type to find
* @return list of aliases
*/
public List<Alias> getAliases(String aliasListName, AliasIDType type)
{
List<Alias> aliases = new ArrayList<>();
for(Alias alias : mAliases)
{
if(alias.hasList() && alias.getAliasListName().equalsIgnoreCase(aliasListName))
{
for(AliasID aliasID: alias.getAliasIdentifiers())
{
if(aliasID.getType() == type)
{
aliases.add(alias);
break;
}
}
}
}
return aliases;
}
/**
* Indicates that one or more of the aliases managed by this model are configured to stream to the specified
* broadcast channel argument.
* @param broadcastChannel to check
* @return true if the broadcast channel is non-null, non-empty and at least one alias is configured to stream to
* the specified stream name.
*/
public boolean hasAliasesWithBroadcastChannel(String broadcastChannel)
{
if(broadcastChannel == null || broadcastChannel.isEmpty())
{
return false;
}
for(Alias alias: mAliases)
{
if(alias.hasBroadcastChannel(broadcastChannel))
{
return true;
}
}
return false;
}
/**
* Updates all aliases configured to stream to the previousStreamName with the updatedStreamName
* @param previousStreamName to be removed
* @param updatedStreamName to be added
*/
public void updateBroadcastChannel(String previousStreamName, String updatedStreamName)
{
if(previousStreamName == null || previousStreamName.isEmpty() || updatedStreamName == null || updatedStreamName.isEmpty())
{
return;
}
for(Alias alias : mAliases)
for(Alias alias: mAliases)
{
if(alias.hasBroadcastChannel(previousName))
if(alias.hasBroadcastChannel(previousStreamName))
{
for(BroadcastChannel broadcastChannel : alias.getBroadcastChannels())
for(BroadcastChannel broadcastChannel: alias.getBroadcastChannels())
{
if(broadcastChannel.getChannelName().contentEquals(previousName))
if(broadcastChannel.getChannelName().contentEquals(previousStreamName))
{
broadcastChannel.setChannelName(newName);
alias.removeAliasID(broadcastChannel);
if(!alias.hasBroadcastChannel(updatedStreamName))
{
alias.addAliasID(new BroadcastChannel(updatedStreamName));
}
}
}
}
}
}
@Override
public int getRowCount()
/**
* Monitors alias additions and removals and updates alias lists
*/
public class AliasListChangeListener implements ListChangeListener<Alias>
{
return mAliases.size();
}
@Override
public int getColumnCount()
{
return 5;
}
@Override
public String getColumnName(int columnIndex)
{
switch(columnIndex)
@Override
public void onChanged(ListChangeListener.Change<? extends Alias> change)
{
case COLUMN_LIST:
return "List";
case COLUMN_GROUP:
return "Group";
case COLUMN_NAME:
return "Name";
case COLUMN_ICON:
return "Icon";
case COLUMN_COLOR:
return "Color";
while(change.next())
{
if(change.wasAdded())
{
for(Alias alias: change.getAddedSubList())
{
addAliasList(alias.getAliasListName());
if(hasAliasList(alias.getAliasListName()))
{
getAliasList(alias.getAliasListName()).addAlias(alias);
}
}
}
else if(change.wasRemoved())
{
for(Alias alias: change.getRemoved())
{
if(hasAliasList(alias.getAliasListName()))
{
AliasList aliasList = getAliasList(alias.getName());
if(alias != null)
{
aliasList.removeAlias(alias);
}
}
}
}
}
}
return null;
}
@Override
public Class<?> getColumnClass(int columnIndex)
{
if(columnIndex == COLUMN_COLOR)
{
return Integer.class;
}
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex)
{
Alias alias = mAliases.get(rowIndex);
switch(columnIndex)
{
case COLUMN_LIST:
return alias.getList();
case COLUMN_GROUP:
return alias.getGroup();
case COLUMN_NAME:
return alias.getName();
case COLUMN_ICON:
return alias.getIconName();
case COLUMN_COLOR:
return alias.getColor();
}
return null;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
{
throw new IllegalArgumentException("Not yet implemented");
}
public void broadcast(AliasEvent event)
{
Alias alias = event.getAlias();
//Validate the alias following a user action that changed the alias or any alias IDs
if(alias != null)
{
alias.validate();
}
if(event.getEvent() == AliasEvent.Event.CHANGE)
{
int index = mAliases.indexOf(event.getAlias());
fireTableRowsUpdated(index, index);
}
mAliasEventBroadcaster.broadcast(event);
}
public void addListener(Listener<AliasEvent> listener)
{
mAliasEventBroadcaster.addListener(listener);
}
public void removeListener(Listener<AliasEvent> listener)
{
mAliasEventBroadcaster.removeListener(listener);
}
}

View File

@@ -1,333 +0,0 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.alias;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.icon.Icon;
import io.github.dsheirer.icon.IconListCellRenderer;
import io.github.dsheirer.icon.IconManager;
import io.github.dsheirer.icon.IconTableModel;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
public class AliasNameEditor extends Editor<Alias>
{
private static final long serialVersionUID = 1L;
private static ComboBoxModel<String> EMPTY_LIST_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_GROUP_MODEL = new DefaultComboBoxModel<>();
private JComboBox<String> mListCombo = new JComboBox<>(EMPTY_LIST_MODEL);
private JComboBox<String> mGroupCombo = new JComboBox<>(EMPTY_GROUP_MODEL);
private JComboBox<Icon> mIconCombo;
private JTextField mName;
private JButton mButtonColor;
private JButton mBtnIconManager;
private AliasModel mAliasModel;
private IconManager mIconManager;
public AliasNameEditor(AliasModel aliasModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mIconManager = iconManager;
mIconManager.getModel().addTableModelListener(new TableModelListener()
{
@Override
public void tableChanged(TableModelEvent e)
{
refreshIcons();
}
});
init();
}
private void init()
{
setLayout(new MigLayout("fill,wrap 2", "[right][grow,fill]", "[][][][][][][grow]"));
add(new JLabel("Name:"));
mName = new JTextField();
mName.getDocument().addDocumentListener(new DocumentListener()
{
@Override
public void removeUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void insertUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void changedUpdate(DocumentEvent e)
{
}
});
add(mName, "wrap");
add(new JLabel("List:"));
mListCombo.setEditable(true);
mListCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
if(mListCombo.getSelectedItem() != null)
{
List<String> groups = mAliasModel
.getGroupNames((String) mListCombo.getSelectedItem());
if(groups.isEmpty())
{
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
}
else
{
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groups.toArray(new String[groups.size()])));
;
}
}
setModified(true);
}
});
add(mListCombo, "wrap");
add(new JLabel("Group:"));
mGroupCombo.setEditable(true);
mGroupCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mGroupCombo, "wrap");
add(new JLabel("Color:"));
mButtonColor = new JButton("Select ...");
mButtonColor.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Color newColor = JColorChooser.showDialog(
AliasNameEditor.this,
"Choose color for this alias",
(hasItem() ? getItem().getDisplayColor() : null));
if(newColor != null)
{
mButtonColor.setForeground(newColor);
mButtonColor.setBackground(newColor);
setModified(true);
}
}
});
add(mButtonColor, "wrap");
add(new JLabel("Icon:"));
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
IconListCellRenderer renderer = new IconListCellRenderer(mIconManager);
renderer.setPreferredSize(new Dimension(200, 30));
mIconCombo.setRenderer(renderer);
mIconCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mIconCombo, "wrap");
//Dummy place holder
add(new JLabel());
mBtnIconManager = new JButton("Icon Manager");
mBtnIconManager.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
mIconManager.showEditor(AliasNameEditor.this);
}
});
add(mBtnIconManager, "span 2,wrap");
setModified(false);
}
private void refreshIcons()
{
if(mIconCombo != null)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
if(hasItem())
{
String iconName = getItem().getIconName();
Icon aliasIcon = mIconManager.getModel().getIcon(iconName);
if(aliasIcon != null)
{
mIconCombo.setSelectedItem(aliasIcon);
}
}
}
});
}
}
@Override
public void setItem(Alias alias)
{
super.setItem(alias);
if(hasItem())
{
mName.setText(alias.getName());
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
List<String> listNames = mAliasModel.getListNames();
if(listNames.isEmpty())
{
mListCombo.setModel(EMPTY_LIST_MODEL);
}
else
{
mListCombo.setModel(new DefaultComboBoxModel<String>(
listNames.toArray(new String[listNames.size()])));
;
}
mListCombo.setSelectedItem(alias.getList());
List<String> groupNames = mAliasModel.getGroupNames(alias.getList());
if(groupNames.isEmpty())
{
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
}
else
{
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groupNames.toArray(new String[groupNames.size()])));
;
}
mGroupCombo.setSelectedItem(alias.getGroup());
Color color = alias.getDisplayColor();
mButtonColor.setBackground(color);
mButtonColor.setForeground(color);
String iconName = alias.getIconName();
if(iconName == null)
{
iconName = IconTableModel.DEFAULT_ICON;
}
Icon savedIcon = mIconManager.getModel().getIcon(iconName);
if(savedIcon != null)
{
mIconCombo.setSelectedItem(savedIcon);
}
}
else
{
mListCombo.setModel(EMPTY_LIST_MODEL);
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
mName.setText(null);
mButtonColor.setBackground(getBackground());
mButtonColor.setForeground(getForeground());
}
repaint();
setModified(false);
}
@Override
public void save()
{
if(hasItem() && isModified())
{
Alias alias = getItem();
if(mListCombo.getSelectedItem() != null)
{
alias.setList((String) mListCombo.getSelectedItem());
}
if(mGroupCombo.getSelectedItem() != null)
{
alias.setGroup((String) mGroupCombo.getSelectedItem());
}
alias.setName(mName.getText());
alias.setColor(mButtonColor.getBackground().getRGB());
if(mIconCombo.getSelectedItem() != null)
{
alias.setIconName(((Icon) mIconCombo.getSelectedItem()).getName());
}
setModified(false);
//Broadcast an alias change event to save the updates
mAliasModel.broadcast(new AliasEvent(getItem(), AliasEvent.Event.CHANGE));
}
}
}

View File

@@ -1,121 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias;
import javax.swing.*;
import javax.swing.event.DocumentListener;
public abstract class ComponentEditor<T> extends JPanel implements DocumentListener
{
private static final long serialVersionUID = 1L;
private boolean mModified;
private ComponentModificationListener mListener;
protected T mComponent;
/**
* Abstract class for editor with notifications when contents are modified
* and methods for saving or resetting the component values with the
* contents of the editor.
*/
public ComponentEditor( T component )
{
mComponent = component;
}
public ComponentEditor()
{
}
public void dispose()
{
mComponent = null;
mListener = null;
}
public T getComponent()
{
return mComponent;
}
protected void setModified( boolean modified )
{
mModified = modified;
if( modified && mListener != null )
{
mListener.componentModified();
}
}
/**
* Indicates if the contents of the editor have been modified
*/
public boolean isModified()
{
return mModified;
}
public void setComponentModificationListener( ComponentModificationListener listener )
{
mListener = listener;
}
/**
* Sets or resets the editable component
*/
public abstract void setComponent( T t );
/**
* Saves changed editor values to the component
*/
public abstract void save();
/**
* Reloads the editor contents from the source component and resets the
* modified flag
*/
public void reset()
{
setComponent( getComponent() );
}
/**
* Validate contents of other editors against this component editor before
* saving. Override this method to allow controller to pass other editors
* to this editor for content inspection/validation before indicating that
* this editor passes validation. This allows for validating editor contents
* that are contingent on settings in other editors.
*
* @throws ComponentValidationException if the contents of the editor
* argument cannot be validated, with the exception containing a detailed
* description of the issue.
*/
public void validate( ComponentEditor<?> editor ) throws ComponentValidationException
{
}
/**
* Listener interface to receive notification that the contents of the
* editor have been modified from the original component value and either
* need to be saved or reset
*/
public interface ComponentModificationListener
{
public void componentModified();
}
}

View File

@@ -1,14 +0,0 @@
package io.github.dsheirer.alias;
public class ComponentValidationException extends Exception
{
private static final long serialVersionUID = 1L;
/**
* Component editor contents validation error
*/
public ComponentValidationException( String message )
{
super( message );
}
}

View File

@@ -1,466 +0,0 @@
package io.github.dsheirer.alias;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.alias.id.priority.Priority;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.icon.Icon;
import io.github.dsheirer.icon.IconListCellRenderer;
import io.github.dsheirer.icon.IconManager;
import io.github.dsheirer.sample.Listener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
public class MultipleAliasEditor extends Editor<List<Alias>>
implements Listener<AliasEvent>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(MultipleAliasEditor.class);
private static String HELP_TEXT =
"<html>Select attributes below to change for all selected aliases</html>";
private JLabel mAliasCountLabel;
private JLabel mAliasCount;
private JCheckBox mListCheckBox = new JCheckBox("List");
private JComboBox<String> mListCombo = new JComboBox<>();
private JCheckBox mGroupCheckBox = new JCheckBox("Group");
private JComboBox<String> mGroupCombo = new JComboBox<>();
private JCheckBox mIconCheckBox = new JCheckBox("Icon");
private JComboBox<Icon> mIconCombo;
private JCheckBox mColorCheckBox = new JCheckBox("Color");
private JButton mButtonColor;
private JButton mBtnIconManager;
private JCheckBox mRecordCheckBox = new JCheckBox("Record");
private JComboBox<Record> mRecordActionCombo = new JComboBox<>(Record.values());
private JCheckBox mPriorityCheckBox = new JCheckBox("Priority");
private JSlider mPrioritySlider;
private JLabel mPrioritySliderLabel;
private JCheckBox mStreamCheckBox = new JCheckBox("Stream");
private JComboBox<String> mStreamCombo;
private AliasModel mAliasModel;
private BroadcastModel mBroadcastModel;
private IconManager mIconManager;
public MultipleAliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mBroadcastModel = broadcastModel;
mIconManager = iconManager;
mAliasModel.addListener(this);
mIconManager.getModel().addTableModelListener(new TableModelListener()
{
@Override
public void tableChanged(TableModelEvent e)
{
refreshIcons();
}
});
init();
}
public List<Alias> getAliases()
{
if (hasItem())
{
return (List<Alias>) getItem();
}
return null;
}
public void init()
{
setLayout(new MigLayout("fill,wrap 2", "[grow,fill][grow,fill]",
"[][][][][][][][][][][][][][grow,fill]"));
mAliasCountLabel = new JLabel("Alias:");
add(mAliasCountLabel);
mAliasCount = new JLabel("Multiple");
add(mAliasCount, "span");
add(new JSeparator(), "span");
add(new JLabel(HELP_TEXT), "span");
add(mListCheckBox);
mListCombo.setEditable(true);
add(mListCombo, "wrap");
add(mGroupCheckBox);
mGroupCombo.setEditable(true);
add(mGroupCombo, "wrap");
add(mColorCheckBox);
mButtonColor = new JButton("Select ...");
mButtonColor.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Color newColor = JColorChooser.showDialog(
MultipleAliasEditor.this,
"Choose color for this alias", null);
if (newColor != null)
{
mButtonColor.setForeground(newColor);
mButtonColor.setBackground(newColor);
}
}
});
add(mButtonColor, "wrap");
add(mIconCheckBox);
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
IconListCellRenderer renderer = new IconListCellRenderer(mIconManager);
renderer.setPreferredSize(new Dimension(200, 30));
mIconCombo.setRenderer(renderer);
add(mIconCombo, "wrap");
//Dummy place holder
add(new JLabel());
mBtnIconManager = new JButton("Icon Manager");
mBtnIconManager.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
mIconManager.showEditor(MultipleAliasEditor.this);
}
});
add(mBtnIconManager, "span,wrap");
add(mRecordCheckBox);
add(mRecordActionCombo);
//Placeholder
add(new JLabel(" "));
mPrioritySliderLabel = new JLabel("Audio Priority: " + Priority.MIN_PRIORITY);
add(mPrioritySliderLabel);
add(mPriorityCheckBox);
mPrioritySlider = new JSlider(JSlider.HORIZONTAL,
Priority.MIN_PRIORITY,
Priority.MAX_PRIORITY + 1,
Priority.MIN_PRIORITY);
mPrioritySlider.setMajorTickSpacing(20);
mPrioritySlider.setMinorTickSpacing(5);
mPrioritySlider.setPaintTicks(true);
mPrioritySlider.setLabelTable(mPrioritySlider.createStandardLabels(25, 25));
mPrioritySlider.setPaintLabels(true);
mPrioritySlider.addChangeListener(new ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
int priority = mPrioritySlider.getValue();
if (priority > Priority.MAX_PRIORITY)
{
mPrioritySliderLabel.setText("Audio Priority: Do Not Monitor");
}
else
{
mPrioritySliderLabel.setText("Audio Priority: " + mPrioritySlider.getValue());
}
}
});
mPrioritySlider.setToolTipText(HELP_TEXT);
add(mPrioritySlider);
add(mStreamCheckBox);
mStreamCombo = new JComboBox<String>();
mStreamCombo.setEditable(true);
add(mStreamCombo, "wrap");
JButton saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
save();
}
});
add(saveButton);
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
reset();
}
});
add(resetButton);
setModified(false);
}
private void refreshIcons()
{
if(mIconCombo != null)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
}
});
}
}
@Override
public void setItem(List<Alias> item)
{
super.setItem(item);
StringBuilder sb = new StringBuilder();
sb.append("Multiple Selected [ ");
if (hasItem())
{
sb.append(String.valueOf(getAliases().size()));
}
else
{
sb.append("0");
}
sb.append(" ]");
mAliasCount.setText(sb.toString());
List<String> listNames = mAliasModel.getListNames();
listNames.add(0, "");
mListCombo.setModel(new DefaultComboBoxModel<String>(
listNames.toArray(new String[listNames.size()])));
List<String> groupNames = mAliasModel.getGroupNames();
groupNames.add(0, "");
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groupNames.toArray(new String[groupNames.size()])));
List<String> streamNames = mBroadcastModel.getBroadcastConfigurationNames();
mStreamCombo.setModel(new DefaultComboBoxModel<String>(streamNames.toArray(new String[streamNames.size()])));
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
setCheckBoxesUnselected();
setModified(false);
}
private void setCheckBoxesUnselected()
{
mListCheckBox.setSelected(false);
mGroupCheckBox.setSelected(false);
mColorCheckBox.setSelected(false);
mIconCheckBox.setSelected(false);
mRecordCheckBox.setSelected(false);
mPriorityCheckBox.setSelected(false);
mStreamCheckBox.setSelected(false);
}
@Override
public void reset()
{
List<String> listNames = mAliasModel.getListNames();
listNames.add(0, "");
mListCombo.setModel(new DefaultComboBoxModel<String>(
listNames.toArray(new String[listNames.size()])));
List<String> groupNames = mAliasModel.getGroupNames();
groupNames.add(0, "");
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groupNames.toArray(new String[groupNames.size()])));
mButtonColor.setForeground(getForeground());
mButtonColor.setBackground(getBackground());
super.reset();
}
private boolean hasRequestedChanges()
{
return mListCheckBox.isSelected() ||
mGroupCheckBox.isSelected() ||
mColorCheckBox.isSelected() ||
mIconCheckBox.isSelected() ||
mRecordCheckBox.isSelected() ||
mPriorityCheckBox.isSelected() ||
mStreamCheckBox.isSelected();
}
@Override
public void save()
{
if (hasRequestedChanges() && hasItem())
{
List<Alias> aliases = getAliases();
for (Alias alias : aliases)
{
if (mListCheckBox.isSelected())
{
String list = null;
if (mListCombo.getSelectedItem() != null)
{
list = (String) mListCombo.getSelectedItem();
}
alias.setList(list);
}
if (mGroupCheckBox.isSelected())
{
String group = null;
if (mGroupCombo.getSelectedItem() != null)
{
group = (String) mGroupCombo.getSelectedItem();
}
alias.setGroup(group);
}
if (mColorCheckBox.isSelected())
{
alias.setColor(mButtonColor.getForeground().getRGB());
}
if (mIconCheckBox.isSelected())
{
if (mIconCombo.getSelectedItem() != null)
{
alias.setIconName(((Icon)mIconCombo.getSelectedItem()).getName());
}
else
{
alias.setIconName(null);
}
}
if (mRecordCheckBox.isSelected())
{
Record action =
(Record) mRecordActionCombo.getSelectedItem();
alias.setRecordable(action == Record.RECORDABLE);
}
if (mPriorityCheckBox.isSelected())
{
int priority = mPrioritySlider.getValue();
//This is a work-around -- we use max priority + 1 in the
//gui to indicate do not monitor, and change the value here
if (priority == Priority.MAX_PRIORITY + 1)
{
priority = Priority.DO_NOT_MONITOR;
}
alias.setCallPriority(priority);
}
if(mStreamCheckBox.isSelected())
{
if(mStreamCombo.getSelectedItem() != null)
{
String streamName = (String)mStreamCombo.getSelectedItem();
boolean hasChannel = false;
//Ensure the alias doesn't already have the channel
for(BroadcastChannel channel: alias.getBroadcastChannels())
{
if(channel.getChannelName().equals(streamName))
{
hasChannel = true;
continue;
}
}
if(!hasChannel)
{
BroadcastChannel channel = (BroadcastChannel)AliasFactory
.getAliasID(AliasIDType.BROADCAST_CHANNEL);
channel.setChannelName(streamName);
alias.addAliasID(channel);
}
}
}
}
for (Alias alias : aliases)
{
//Broadcast an alias change event to save the updates
mAliasModel.broadcast(new AliasEvent(alias, AliasEvent.Event.CHANGE));
}
}
}
@Override
public void receive(AliasEvent event)
{
if (event.getEvent() == AliasEvent.Event.DELETE &&
hasItem() &&
getAliases().contains(event.getAlias()))
{
getAliases().remove(event.getAlias());
setItem(getAliases());
}
}
public enum Record
{
NON_RECORDABLE("Non-Recordable"),
RECORDABLE("Recordable");
private String mLabel;
private Record(String label)
{
mLabel = label;
}
public String toString()
{
return mLabel;
}
}
}

View File

@@ -1,379 +0,0 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.alias;
import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.alias.id.priority.Priority;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class PatchGroupAlias extends Alias
{
private final static Logger mLog = LoggerFactory.getLogger(PatchGroupAlias.class);
private Alias mPatchGroupAlias;
private List<Alias> mPatchedAliases = new ArrayList<>();
private List<String> mPatchedTalkgroupIDs = new ArrayList<>();
/**
* Patch group alias is a single alias for a group of aliases that are temporarily patched together. This will
* normally be used for patched talkgroups, but could be used with any type of alias identifiers that can be
* temporarily joined to form a patch group.
*
* Alias properties such as recordable, streamable and call priority are an aggregation from the set of patched
* aliases contained in this patch group alias and the patch group ID alias and where applicable, return the highest
* value/priority from the group of patched aliases.
*/
public PatchGroupAlias()
{
}
@Override
public int getColor()
{
if(mPatchGroupAlias != null)
{
return mPatchGroupAlias.getColor();
}
return super.getColor();
}
/**
* Sets an alias for this patch group ID
*/
public void setPatchGroupAlias(Alias alias)
{
mPatchGroupAlias = alias;
}
/**
* Alias for this patch group
*/
public Alias getPatchGroupAlias()
{
return mPatchGroupAlias;
}
/**
* Indicates if this patch group has an alias
*/
public boolean hasPatchGroupAlias()
{
return mPatchGroupAlias != null;
}
/**
* List of patched aliases contained in this patch group
*/
public List<Alias> getPatchedAliases()
{
return mPatchedAliases;
}
/**
* Removes/clears all patched aliases from this patch alias group
*/
public void clearPatchedAliases()
{
mPatchedAliases.clear();
}
/**
* Adds the patched alias to this patch alias group
*/
public void addPatchedAlias(Alias alias)
{
if(alias == PatchGroupAlias.this)
{
throw new IllegalArgumentException("Can't add patch group alias to itself - would create an infinite loop");
}
mPatchedAliases.add(alias);
}
/**
* Removes the patched alias from this patch alias group
*/
public void removePatchedAlias(Alias alias)
{
mPatchedAliases.remove(alias);
}
/**
* Sets the list of patched talkgroup IDs for this patch group
*/
public void setPatchedTalkgroupIDs(List<String> talkgroupIDs)
{
mPatchedTalkgroupIDs = talkgroupIDs;
}
/**
* List of patched talkgroup IDs for this patch group
*/
public List<String> getPatchedTalkgroupIDs()
{
return mPatchedTalkgroupIDs;
}
@Override
public String getName()
{
if(hasPatchGroupAlias())
{
return getPatchGroupAlias().getName();
}
else
{
for(AliasID id: getId())
{
if(id.getType() == AliasIDType.TALKGROUP)
{
return "PATCH:" + ((TalkgroupID)id).getTalkgroup();
}
}
}
return "PATCH:****";
}
@Override
public List<AliasAction> getAction()
{
List<AliasAction> aliasActions = new ArrayList<>();
if(hasPatchGroupAlias())
{
aliasActions.addAll(getPatchGroupAlias().getAction());
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias))
{
for(AliasAction action: alias.getAction())
{
if(!aliasActions.contains(action))
{
aliasActions.add(action);
}
}
}
}
return aliasActions;
}
@Override
public boolean hasActions()
{
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.hasActions())
{
return true;
}
}
return hasPatchGroupAlias() && getPatchGroupAlias().hasActions();
}
/**
* Returns the highest listenable audio priority defined among the aliases in the group, or returns 'Do Not Monitor'
* if that is the only priority defined. Otherwise, returns default (100) priority.
*/
@Override
public int getCallPriority()
{
boolean hasDoNotMonitor = false;
int highestPriority = (hasPatchGroupAlias() ? getPatchGroupAlias().getCallPriority() : Priority.DEFAULT_PRIORITY + 1);
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.hasCallPriority() && alias.getCallPriority() < highestPriority)
{
if(alias.getCallPriority() == Priority.DO_NOT_MONITOR)
{
hasDoNotMonitor = true;
}
else
{
highestPriority = alias.getCallPriority();
}
}
}
if(highestPriority <= Priority.DEFAULT_PRIORITY)
{
return highestPriority;
}
else if(hasDoNotMonitor)
{
return Priority.DO_NOT_MONITOR;
}
else
{
return Priority.DEFAULT_PRIORITY;
}
}
@Override
public boolean hasCallPriority()
{
if(hasPatchGroupAlias() && getPatchGroupAlias().hasCallPriority())
{
return true;
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.hasCallPriority())
{
return true;
}
}
return false;
}
@Override
public boolean isRecordable()
{
if(hasPatchGroupAlias() && getPatchGroupAlias().isRecordable())
{
return true;
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.isRecordable())
{
return true;
}
}
return false;
}
@Override
public boolean isStreamable()
{
if(hasPatchGroupAlias() && getPatchGroupAlias().isStreamable())
{
return true;
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.isStreamable())
{
return true;
}
}
return false;
}
@Override
public Set<BroadcastChannel> getBroadcastChannels()
{
Set<BroadcastChannel> broadcastChannels = new TreeSet<>();
if(hasPatchGroupAlias())
{
broadcastChannels.addAll(getPatchGroupAlias().getBroadcastChannels());
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias))
{
broadcastChannels.addAll(alias.getBroadcastChannels());
}
}
return broadcastChannels;
}
@Override
public boolean hasBroadcastChannel(String channel)
{
if(hasPatchGroupAlias() && getPatchGroupAlias().hasBroadcastChannel(channel))
{
return true;
}
for(Alias alias: mPatchedAliases)
{
if(!(alias instanceof PatchGroupAlias) && alias.hasBroadcastChannel(channel))
{
return true;
}
}
return false;
}
public static void main(String[] args)
{
Alias a1 = new Alias("Alias 1");
a1.addAliasID(new BroadcastChannel("Channel 1"));
a1.addAliasID(new BroadcastChannel("Channel 2"));
a1.addAliasID(new BroadcastChannel("Channel 3"));
a1.addAliasID(new BroadcastChannel("Channel 4"));
Alias a2 = new Alias("Alias 1");
a1.addAliasID(new BroadcastChannel("Channel 1"));
a1.addAliasID(new BroadcastChannel("Channel 2"));
a1.addAliasID(new BroadcastChannel("Channel 3"));
a1.addAliasID(new BroadcastChannel("Channel 4"));
Alias a3 = new Alias("Alias 1");
a1.addAliasID(new BroadcastChannel("Channel 1"));
a1.addAliasID(new BroadcastChannel("Channel 2"));
a1.addAliasID(new BroadcastChannel("Channel 3"));
a1.addAliasID(new BroadcastChannel("Channel 4"));
Alias a4 = new Alias("Alias 1");
a1.addAliasID(new BroadcastChannel("Channel 1"));
a1.addAliasID(new BroadcastChannel("Channel 2"));
a1.addAliasID(new BroadcastChannel("Channel 3"));
a1.addAliasID(new BroadcastChannel("Channel 4"));
PatchGroupAlias pga = new PatchGroupAlias();
pga.setPatchGroupAlias(a1);
pga.addPatchedAlias(a2);
pga.addPatchedAlias(a3);
pga.addPatchedAlias(a4);
Set<BroadcastChannel> bc = pga.getBroadcastChannels();
mLog.debug("Channels:" + bc);
}
}

View File

@@ -26,9 +26,10 @@ import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.action.beep.BeepAction;
import io.github.dsheirer.alias.action.clip.ClipAction;
import io.github.dsheirer.alias.action.script.ScriptAction;
import io.github.dsheirer.message.Message;
import java.util.concurrent.ScheduledExecutorService;
import io.github.dsheirer.message.IMessage;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.util.Callback;
/**
* Alias action defines an action to execute when an alias is detected active.
@@ -43,10 +44,33 @@ import java.util.concurrent.ScheduledExecutorService;
@JacksonXmlRootElement(localName = "action")
public abstract class AliasAction
{
private SimpleStringProperty mValueProperty = new SimpleStringProperty();
public AliasAction()
{
}
/**
* String property representation of this alias ID
*/
@JsonIgnore
public SimpleStringProperty valueProperty()
{
return mValueProperty;
}
/**
* Updates the value property for this alias ID. Note: this method is intended to be invoked by all subclasses
* each time that any of the subclass member variable values change.
*/
public void updateValueProperty()
{
valueProperty().set(toString());
//Hack: harmless, but the list extractor does not consistently update unless we do this.
valueProperty().get();
}
@JsonIgnore
public abstract AliasActionType getType();
@@ -56,10 +80,18 @@ public abstract class AliasAction
* action attached. The alias argument is the parent alias containing the
* alias action.
*/
public abstract void execute(ScheduledExecutorService scheduledExecutorService, Alias alias, Message message);
public abstract void execute(Alias alias, IMessage message);
/**
* Dismiss a persistent alias action
*/
public abstract void dismiss(boolean reset);
/**
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
*/
public static Callback<AliasAction,Observable[]> extractor()
{
return (AliasAction aliasAction) -> new Observable[] {aliasAction.valueProperty()};
}
}

View File

@@ -1,339 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.action;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasEvent;
import io.github.dsheirer.alias.AliasEvent.Event;
import io.github.dsheirer.alias.AliasFactory;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EmptyEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AliasActionEditor extends Editor<Alias>
{
private static final long serialVersionUID = 1L;
private static ListModel<AliasAction> EMPTY_MODEL = new DefaultListModel<>();
private JList<AliasAction> mAliasActionList = new JList<>( EMPTY_MODEL );
private JButton mNewActionButton;
private JButton mCloneActionButton;
private JButton mDeleteActionButton;
private EditorContainer mEditorContainer = new EditorContainer();
private AliasModel mAliasModel;
public AliasActionEditor( AliasModel model )
{
mAliasModel = model;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 3",
"[grow,fill][grow,fill][grow,fill]", "[][grow,fill][]" ) );
mAliasActionList.setVisibleRowCount( 6 );
mAliasActionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
mAliasActionList.setLayoutOrientation( JList.VERTICAL );
mAliasActionList.addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
JList<?> list = (JList<?>)event.getSource();
Object selectedItem = list.getSelectedValue();
if( selectedItem != null && selectedItem instanceof AliasAction )
{
AliasAction selected = (AliasAction)selectedItem;
mEditorContainer.setAliasAction( selected );
mCloneActionButton.setEnabled( true );
mDeleteActionButton.setEnabled( true );
}
else
{
mCloneActionButton.setEnabled( false );
mDeleteActionButton.setEnabled( false );
}
}
}
} );
JScrollPane scroller = new JScrollPane( mAliasActionList );
add( scroller, "span,grow" );
add( mEditorContainer, "span,grow" );
mNewActionButton = new JButton( "New ..." );
mNewActionButton.setToolTipText( "Create a new Alias Action" );
mNewActionButton.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JPopupMenu menu = new JPopupMenu();
menu.add( new AddAliasActionItem( AliasActionType.BEEP ) );
menu.add( new AddAliasActionItem( AliasActionType.CLIP ) );
menu.add( new AddAliasActionItem( AliasActionType.SCRIPT ) );
menu.show( e.getComponent(), e.getX(), e.getY() );
}
} );
add( mNewActionButton );
mCloneActionButton = new JButton( "Clone" );
mCloneActionButton.setToolTipText( "Create a copy of the currently selected action" );
mCloneActionButton.setEnabled( false );
mCloneActionButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
AliasAction selected = mAliasActionList.getSelectedValue();
if( selected != null )
{
AliasAction clone = AliasFactory.copyOf( selected );
if( clone != null )
{
addAliasActionToList( clone );
}
}
}
} );
add( mCloneActionButton );
mDeleteActionButton = new JButton( "Delete" );
mDeleteActionButton.setToolTipText( "Delete the currently selected action" );
mDeleteActionButton.setEnabled( false );
mDeleteActionButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final AliasAction selected = mAliasActionList.getSelectedValue();
if( selected != null )
{
int choice = JOptionPane.showConfirmDialog( mDeleteActionButton,
"Do you want to delete [" + selected.toString() + "]",
"Are you sure?", JOptionPane.YES_NO_OPTION );
if( choice == JOptionPane.YES_OPTION && hasItem() )
{
Alias alias = getItem();
alias.removeAliasAction( selected );
mAliasModel.broadcast( new AliasEvent( alias, Event.CHANGE ) );
setItem( alias );
}
}
}
} );
add( mDeleteActionButton, "wrap" );
}
@Override
public void setItem( Alias alias )
{
super.setItem( alias );
if( alias == null || alias.getAction().isEmpty() )
{
mAliasActionList.setModel( EMPTY_MODEL );
}
else
{
DefaultListModel<AliasAction> model = new DefaultListModel<>();
List<AliasAction> actions = alias.getAction();
Collections.sort( actions, new Comparator<AliasAction>()
{
@Override
public int compare( AliasAction o1, AliasAction o2 )
{
return o1.toString().compareTo( o2.toString() );
}
} );
for( AliasAction action: actions )
{
model.addElement( action );
}
mAliasActionList.setModel( model );
}
mEditorContainer.setAliasAction( null );
}
@Override
public void save()
{
if( isModified() || mEditorContainer.isModified() )
{
if( mEditorContainer.isModified() )
{
mEditorContainer.save();
}
setModified( false );
if( hasItem() )
{
mAliasModel.broadcast( new AliasEvent( getItem(), Event.CHANGE ) );
}
}
}
public class EditorContainer extends JPanel
{
private static final long serialVersionUID = 1L;
private Editor<AliasAction> mEditor = new EmptyEditor<>();
public EditorContainer()
{
setLayout( new MigLayout( "","[grow,fill]", "[grow,fill]" ) );
add( mEditor );
}
public boolean isModified()
{
if( mEditor != null )
{
return mEditor.isModified();
}
return false;
}
public void save()
{
if( mEditor != null )
{
mEditor.save();
}
}
public void setAliasAction( AliasAction aliasAction )
{
if( mEditor != null )
{
if( mEditor.isModified() )
{
int option = JOptionPane.showConfirmDialog(
EditorContainer.this,
"Action settings have changed. Do you want to save these changes?",
"Save Changes?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE );
if( option == JOptionPane.YES_OPTION )
{
mEditor.save();
}
}
}
removeAll();
//This will always give us an editor
mEditor = AliasFactory.getEditor( aliasAction );
add( mEditor );
revalidate();
}
}
private void addAliasActionToList( final AliasAction action )
{
if( action != null && hasItem() )
{
final Alias alias = getItem();
alias.addAliasAction( action );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
setItem( alias );
mAliasActionList.setSelectedValue( action, true );
AliasActionEditor.this.setModified( true );
}
} );
}
}
public class AddAliasActionItem extends JMenuItem
{
private static final long serialVersionUID = 1L;
private AliasActionType mAliasActionType;
public AddAliasActionItem( AliasActionType type )
{
super( type.toString() );
mAliasActionType = type;
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final AliasAction action =
AliasFactory.getAliasAction( mAliasActionType );
addAliasActionToList( action );
}
} );
}
}
}

View File

@@ -1,32 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.action;
import io.github.dsheirer.alias.AliasEvent;
/**
* Interface for receiving alias events. Each listener will receive
* notification of all alias events.
*/
public interface AliasActionListener
{
/**
* Notifies the listener that an alias event has occurred
*/
public void aliasChanged( AliasEvent event );
}

View File

@@ -1,69 +1,104 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
*/
package io.github.dsheirer.alias.action;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.IMessageListener;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Manages all alias action events. Each received message is interrogated for
* any alias entries and then each alias is interrogated for any alias actions.
* Manages all alias action events. Each received message is interrogated for any identifiers that may be aliasable
* and have associated alias actions.
*
* Each alias action is executed and provided a copy of the source message so
* that the contents of the message can be used as part of the action.
* Each alias action is executed and provided a copy of the source message so that the contents of the message can be
* used as part of the action.
*/
public class AliasActionManager implements Listener<Message>
public class AliasActionManager extends Module implements IMessageListener, Listener<IMessage>
{
public AliasActionManager()
private final static Logger mLog = LoggerFactory.getLogger(AliasActionManager.class);
private AliasList mAliasList;
public AliasActionManager(AliasList aliasList)
{
mAliasList = aliasList;
}
@Override
public void receive(Message message)
public void receive(IMessage message)
{
if(message.isValid())
if(mAliasList != null && message.isValid())
{
List<Alias> aliases = message.getAliases();
List<Identifier> identifiers = message.getIdentifiers();
if(aliases != null)
for(Identifier identifier: identifiers)
{
for(Alias alias : aliases)
{
if(alias.hasActions())
{
List<AliasAction> actions = alias.getAction();
List<Alias> aliases = mAliasList.getAliases(identifier);
for(AliasAction action : actions)
for(Alias alias: aliases)
{
if(alias != null && alias.hasActions())
{
for(AliasAction action: alias.getAliasActions())
{
/* Provide access to the thread pool manager in case the
* action needs to setup a timer, and provide the original
* message to be used as part of the action (e.g. sending
* the message as a text message to a cell phone */
action.execute(ThreadPool.SCHEDULED, alias, message);
action.execute(alias, message);
}
}
}
}
}
}
@Override
public void reset()
{
//No actions needed
}
@Override
public void start()
{
//No actions needed
}
@Override
public void stop()
{
//No actions neeeded
}
/**
* IMessageListener interface ... delegates to this class implementation of Listener<Message>
*/
@Override
public Listener<IMessage> getMessageListener()
{
return this;
}
}

View File

@@ -1,13 +1,32 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias.action;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.util.ThreadPool;
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -18,19 +37,15 @@ public abstract class RecurringAction extends AliasAction
protected AtomicBoolean mRunning = new AtomicBoolean(false);
@JsonIgnore
private ScheduledFuture<?> mPerpetualAction;
@JsonIgnore
protected ScheduledExecutorService mScheduledExecutorService;
protected Interval mInterval = Interval.ONCE;
protected int mPeriod = 5;
public abstract void performAction(Alias alias, Message message);
public abstract void performAction(Alias alias, IMessage message);
@Override
public void execute(ScheduledExecutorService scheduledExecutorService, Alias alias, Message message)
public void execute(Alias alias, IMessage message)
{
mScheduledExecutorService = scheduledExecutorService;
if(mRunning.compareAndSet(false, true))
{
switch(mInterval)
@@ -41,11 +56,11 @@ public abstract class RecurringAction extends AliasAction
break;
case DELAYED_RESET:
performThreadedAction(alias, message);
mScheduledExecutorService.schedule(new ResetTask(), mPeriod, TimeUnit.SECONDS);
ThreadPool.SCHEDULED.schedule(new ResetTask(), mPeriod, TimeUnit.SECONDS);
break;
case UNTIL_DISMISSED:
mPerpetualAction = mScheduledExecutorService.scheduleAtFixedRate(
new PerformActionTask(alias, message), mPeriod, mPeriod, TimeUnit.SECONDS);
mPerpetualAction = ThreadPool.SCHEDULED.scheduleAtFixedRate(
new PerformActionTask(alias, message), 0, mPeriod, TimeUnit.SECONDS);
StringBuilder sb = new StringBuilder();
sb.append("<html><div width='250'>Alias [");
@@ -56,18 +71,13 @@ public abstract class RecurringAction extends AliasAction
final String text = sb.toString();
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
JOptionPane.showMessageDialog(null, text,
"Alias Alert", JOptionPane.INFORMATION_MESSAGE);
EventQueue.invokeLater(() -> {
JOptionPane.showMessageDialog(null, text,
"Alias Alert", JOptionPane.INFORMATION_MESSAGE);
dismiss(false);
dismiss(false);
mScheduledExecutorService.schedule(new ResetTask(), 15, TimeUnit.SECONDS);
}
ThreadPool.SCHEDULED.schedule(new ResetTask(), 15, TimeUnit.SECONDS);
});
break;
default:
@@ -79,16 +89,9 @@ public abstract class RecurringAction extends AliasAction
* Spawns the performAction() event into a new thread so that it doesn't
* delay any decoder actions.
*/
private void performThreadedAction(final Alias alias, final Message message)
private void performThreadedAction(final Alias alias, final IMessage message)
{
mScheduledExecutorService.schedule(new Runnable()
{
@Override
public void run()
{
performAction(alias, message);
}
}, 0, TimeUnit.SECONDS);
ThreadPool.CACHED.execute(() -> performAction(alias, message));
}
@Override
@@ -116,6 +119,7 @@ public abstract class RecurringAction extends AliasAction
public void setPeriod(int period)
{
mPeriod = period;
updateValueProperty();
}
@JacksonXmlProperty(isAttribute = true, localName = "interval")
@@ -127,19 +131,19 @@ public abstract class RecurringAction extends AliasAction
public void setInterval(Interval interval)
{
mInterval = interval;
mRunning.set(false);
updateValueProperty();
}
public enum Interval
{
ONCE("Once"),
DELAYED_RESET("Once, Reset After Delay"),
DELAYED_RESET("Once - Reset After Delay"),
UNTIL_DISMISSED("Until Dismissed");
private String mLabel;
private Interval(String label)
Interval(String label)
{
mLabel = label;
}
@@ -153,9 +157,9 @@ public abstract class RecurringAction extends AliasAction
public class PerformActionTask implements Runnable
{
private Alias mAlias;
private Message mMessage;
private IMessage mMessage;
public PerformActionTask(Alias alias, Message message)
public PerformActionTask(Alias alias, IMessage message)
{
mAlias = alias;
mMessage = message;

View File

@@ -1,13 +1,65 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias.action.beep;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.action.AliasActionType;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.audio.AudioFormats;
import io.github.dsheirer.gui.preference.playback.ToneFrequency;
import io.github.dsheirer.gui.preference.playback.ToneUtil;
import io.github.dsheirer.gui.preference.playback.ToneVolume;
import io.github.dsheirer.message.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
public class BeepAction extends RecurringAction
{
private static final Logger mLog = LoggerFactory.getLogger(BeepAction.class);
private byte[] mToneBytes;
public BeepAction()
{
setInterval(Interval.ONCE);
float[] tone = ToneUtil.getTone(ToneFrequency.F700, ToneVolume.V10, 1000);
/* Little-endian byte buffer */
ByteBuffer buffer = ByteBuffer.allocate(tone.length * 2).order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer shortBuffer = buffer.asShortBuffer();
for(float sample : tone)
{
shortBuffer.put((short) (sample * Short.MAX_VALUE));
}
mToneBytes = buffer.array();
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@Override
@@ -17,14 +69,50 @@ public class BeepAction extends RecurringAction
}
@Override
public void performAction(Alias alias, Message message )
public void performAction(Alias alias, IMessage message )
{
System.out.println( "\007" );
DataLine.Info info = new DataLine.Info(Clip.class, AudioFormats.PCM_SIGNED_8000_HZ_16_BIT_MONO);
if(!AudioSystem.isLineSupported(info))
{
mLog.error("Audio clip playback is not supported on this system");
return;
}
try
{
Clip clip = (Clip)AudioSystem.getLine(info);
clip.open(AudioFormats.PCM_SIGNED_8000_HZ_16_BIT_MONO, mToneBytes, 0, mToneBytes.length);
clip.start();
}
catch(Exception e)
{
mLog.error("Error attempting to play audio test tone");
}
}
@Override
public String toString()
{
return "Beep";
StringBuilder sb = new StringBuilder();
sb.append("Beep");
if(getInterval() != null)
{
switch(getInterval())
{
case ONCE:
sb.append(" Once");
break;
case DELAYED_RESET:
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
break;
case UNTIL_DISMISSED:
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
break;
}
}
return sb.toString();
}
}

View File

@@ -1,185 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.action.beep;
import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BeepActionEditor extends DocumentListenerEditor<AliasAction>
{
private static final long serialVersionUID = 1L;
private static final String HELP_TEXT =
"<html><h3>Beep Action</h3>"
+ "This action will sound a beep according to the interval<br>"
+ "that you select:<br><br>"
+ "<b>Once:</b> Beep the first time the alias is active and<br>"
+ "never again<br><br>"
+ "<b>Once, Reset After Delay:</b> Beep once and suppress<br>"
+ "subsequent beeps for the specified period in seconds.<br>"
+ "After the reset period, beep again when the alias is active.<br><br>"
+ "<b>Until Dismissed:</b> Beep every period seconds until you<br>"
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
+ "for 15 seconds after you click OK.<br>"
+ "</html>";
private JComboBox<RecurringAction.Interval> mComboInterval;
private JSlider mPeriodSlider;
private JLabel mPeriodSliderLabel;
public BeepActionEditor( AliasAction aliasAction )
{
init();
setItem( aliasAction );
}
public BeepAction getBeepAction()
{
if( getItem() instanceof BeepAction )
{
return (BeepAction)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][]" ) );
add( new JLabel( "Beep Interval:" ) );
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
RecurringAction.Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period spinner based on selection */
boolean enabled = selected != RecurringAction.Interval.ONCE;
mPeriodSlider.setEnabled( enabled );
mPeriodSliderLabel.setEnabled( enabled );
}
setModified( true );
}
});
add( mComboInterval, "wrap" );
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
model.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
setModified( true );
}
} );
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
mPeriodSlider.setMajorTickSpacing( 10 );
mPeriodSlider.setMinorTickSpacing( 2 );
mPeriodSlider.setPaintTicks( true );
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
mPeriodSlider.setPaintLabels( true );
mPeriodSlider.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
setModified( true );
}
} );
mPeriodSlider.setToolTipText( HELP_TEXT );
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
add( mPeriodSliderLabel );
add( mPeriodSlider, "wrap,grow" );
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( BeepActionEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
@Override
public void setItem( AliasAction item )
{
super.setItem( item );
if( hasItem() )
{
BeepAction beep = getBeepAction();
RecurringAction.Interval interval = beep.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != RecurringAction.Interval.ONCE;
mPeriodSliderLabel.setEnabled( enabled );
mPeriodSlider.setEnabled( enabled );
mPeriodSlider.setValue( beep.getPeriod() );
}
setModified( false );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
BeepAction beep = getBeepAction();
beep.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
beep.setPeriod( mPeriodSlider.getValue() );
}
setModified( false );
}
}

View File

@@ -1,3 +1,23 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.action.clip;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -5,7 +25,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.action.AliasActionType;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,6 +45,7 @@ public class ClipAction extends RecurringAction
public ClipAction()
{
updateValueProperty();
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@@ -42,10 +63,11 @@ public class ClipAction extends RecurringAction
public void setPath(String path)
{
mFilePath = path;
updateValueProperty();
}
@Override
public void performAction(Alias alias, Message message)
public void performAction(Alias alias, IMessage message)
{
try
{
@@ -67,8 +89,7 @@ public class ClipAction extends RecurringAction
{
mClip = AudioSystem.getClip();
AudioInputStream ais =
AudioSystem.getAudioInputStream(new File(mFilePath));
AudioInputStream ais = AudioSystem.getAudioInputStream(new File(mFilePath));
mClip.open(ais);
}
@@ -93,17 +114,33 @@ public class ClipAction extends RecurringAction
}
}
@Override
public String toString()
{
if(mFilePath == null)
StringBuilder sb = new StringBuilder();
sb.append("Play Audio Clip");
if(getInterval() != null)
{
return "Play Clip";
switch(getInterval())
{
case ONCE:
sb.append(" Once");
break;
case DELAYED_RESET:
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
break;
case UNTIL_DISMISSED:
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
break;
}
}
else
if(getPath() == null)
{
return "Play Clip: " + mFilePath;
sb.append(" - (audio file empty)");
}
return sb.toString();
}
}

View File

@@ -1,285 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.action.clip;
import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
public class ClipActionEditor extends DocumentListenerEditor<AliasAction>
{
private static final long serialVersionUID = 1L;
private static final String PLEASE_SELECT_A_FILE = "Please select a file";
private static final String HELP_TEXT =
"<html><h3>Clip Action</h3>"
+ "This action will play an audio clip according to the interval<br>"
+ "that you select:<br><br>"
+ "<b>Once:</b> play the first time the alias is active and<br>"
+ "never again<br><br>"
+ "<b>Once, Reset After Delay:</b> play once and suppress<br>"
+ "subsequent runs for the specified period in seconds.<br>"
+ "After the reset period, play again when the alias is active.<br><br>"
+ "<b>Until Dismissed:</b> play every period seconds until you<br>"
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
+ "for 15 seconds after you click OK.<br>"
+ "</html>";
private JComboBox<RecurringAction.Interval> mComboInterval;
private JSlider mPeriodSlider;
private JLabel mPeriodSliderLabel;
private JTextField mTextFilePath;
public ClipActionEditor( AliasAction aliasAction )
{
init();
setItem( aliasAction );
}
public ClipAction getClipAction()
{
if( getItem() instanceof ClipAction )
{
return (ClipAction)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][]" ) );
add( new JLabel( "Play Interval:" ) );
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
RecurringAction.Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period slider based on selection */
boolean enabled = selected != RecurringAction.Interval.ONCE;
mPeriodSlider.setEnabled( enabled );
mPeriodSliderLabel.setEnabled( enabled );
}
setModified( true );
}
});
add( mComboInterval );
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
model.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
setModified( true );
}
} );
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
mPeriodSlider.setMajorTickSpacing( 10 );
mPeriodSlider.setMinorTickSpacing( 2 );
mPeriodSlider.setPaintTicks( true );
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
mPeriodSlider.setPaintLabels( true );
mPeriodSlider.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
setModified( true );
}
} );
mPeriodSlider.setToolTipText( HELP_TEXT );
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
add( mPeriodSliderLabel );
add( mPeriodSlider, "wrap,grow" );
mTextFilePath = new JTextField( PLEASE_SELECT_A_FILE );
add( mTextFilePath, "growx,span" );
JButton fileButton = new JButton( "File" );
fileButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final JFileChooser chooser = new JFileChooser();
int value = chooser.showOpenDialog( ClipActionEditor.this );
if( value == JFileChooser.APPROVE_OPTION )
{
File file = chooser.getSelectedFile();
mTextFilePath.setText( file.getAbsolutePath() );
setModified( true );
}
}
} );
add( fileButton, "grow" );
JButton testButton = new JButton( "Test" );
testButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
if( hasItem() )
{
String path = mTextFilePath.getText();
if( path == null || path.trim().isEmpty() )
{
JOptionPane.showMessageDialog( ClipActionEditor.this,
"Please select an audio file", PLEASE_SELECT_A_FILE,
JOptionPane.ERROR_MESSAGE );
}
else
{
if( isModified() )
{
int option = JOptionPane.showConfirmDialog(
ClipActionEditor.this,
"Settings have changed. Do you want to save these changes?",
"Save Changes?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE );
if( option == JOptionPane.YES_OPTION )
{
save();
}
}
new Thread( new Runnable()
{
@Override
public void run()
{
try
{
getClipAction().play();
}
catch( Exception e1 )
{
JOptionPane.showMessageDialog( ClipActionEditor.this,
"Couldn't play audio clip [" + e1.getMessage() + "]",
"Error", JOptionPane.ERROR_MESSAGE );
}
}
}).start();
}
}
}
} );
add( testButton, "grow,wrap" );
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( ClipActionEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
@Override
public void setItem( AliasAction item )
{
super.setItem( item );
if( hasItem() )
{
ClipAction clip = getClipAction();
RecurringAction.Interval interval = clip.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != RecurringAction.Interval.ONCE;
mPeriodSliderLabel.setEnabled( enabled );
mPeriodSlider.setEnabled( enabled );
mPeriodSlider.setValue( clip.getPeriod() );
String filepath = clip.getPath();
if( filepath != null && !filepath.isEmpty() )
{
mTextFilePath.setText( filepath );
}
else
{
mTextFilePath.setText( PLEASE_SELECT_A_FILE );
}
}
setModified( false );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
ClipAction script = getClipAction();
script.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
script.setPeriod( mPeriodSlider.getValue() );
script.setPath( mTextFilePath.getText() );
}
setModified( false );
}
}

View File

@@ -1,10 +1,30 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.action.script;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.action.AliasActionType;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -19,6 +39,7 @@ public class ScriptAction extends RecurringAction
public ScriptAction()
{
updateValueProperty();
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@@ -36,10 +57,11 @@ public class ScriptAction extends RecurringAction
public void setScript(String script)
{
mScript = script;
updateValueProperty();
}
@Override
public void performAction(Alias alias, Message message)
public void performAction(Alias alias, IMessage message)
{
try
{
@@ -63,8 +85,7 @@ public class ScriptAction extends RecurringAction
int exitCode = p.waitFor();
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
@@ -77,8 +98,7 @@ public class ScriptAction extends RecurringAction
if(exitCode != 0)
{
throw new RuntimeException("Exit Code: " + exitCode +
" Console:" + sb.toString());
throw new RuntimeException("Exit Code: " + exitCode + " Console:" + sb.toString());
}
}
}
@@ -86,13 +106,30 @@ public class ScriptAction extends RecurringAction
@Override
public String toString()
{
if(mScript == null)
StringBuilder sb = new StringBuilder();
sb.append("Run Script");
if(getInterval() != null)
{
return "Run Script";
switch(getInterval())
{
case ONCE:
sb.append(" Once");
break;
case DELAYED_RESET:
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
break;
case UNTIL_DISMISSED:
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
break;
}
}
else
if(getScript() == null)
{
return "Run Script: " + mScript;
sb.append(" - (script file empty)");
}
return sb.toString();
}
}

View File

@@ -1,281 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.action.script;
import io.github.dsheirer.alias.action.AliasAction;
import io.github.dsheirer.alias.action.RecurringAction;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
public class ScriptActionEditor extends DocumentListenerEditor<AliasAction>
{
private static final long serialVersionUID = 1L;
private static final String PLEASE_SELECT_A_FILE = "Please select a file";
private static final String HELP_TEXT =
"<html><h3>Script Action</h3>"
+ "This action will run a script according to the interval<br>"
+ "that you select:<br><br>"
+ "<b>Once:</b> run the first time the alias is active and<br>"
+ "never again<br><br>"
+ "<b>Once, Reset After Delay:</b> run once and suppress<br>"
+ "subsequent runs for the specified period in seconds.<br>"
+ "After the reset period, run again when the alias is active.<br><br>"
+ "<b>Until Dismissed:</b> run every period seconds until you<br>"
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
+ "for 15 seconds after you click OK.<br>"
+ "</html>";
private JComboBox<RecurringAction.Interval> mComboInterval;
private JSlider mPeriodSlider;
private JLabel mPeriodSliderLabel;
private JTextField mTextFilePath;
public ScriptActionEditor( AliasAction aliasAction )
{
init();
setItem( aliasAction );
}
public ScriptAction getScriptAction()
{
if( getItem() instanceof ScriptAction )
{
return (ScriptAction)getItem();
}
return null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][]" ) );
add( new JLabel( "Run Interval:" ) );
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
RecurringAction.Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period slider based on selection */
boolean enabled = selected != RecurringAction.Interval.ONCE;
mPeriodSlider.setEnabled( enabled );
mPeriodSliderLabel.setEnabled( enabled );
}
setModified( true );
}
});
add( mComboInterval );
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
model.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
setModified( true );
}
} );
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
mPeriodSlider.setMajorTickSpacing( 10 );
mPeriodSlider.setMinorTickSpacing( 2 );
mPeriodSlider.setPaintTicks( true );
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
mPeriodSlider.setPaintLabels( true );
mPeriodSlider.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
setModified( true );
}
} );
mPeriodSlider.setToolTipText( HELP_TEXT );
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
add( mPeriodSliderLabel );
add( mPeriodSlider, "wrap,grow" );
mTextFilePath = new JTextField( PLEASE_SELECT_A_FILE );
add( mTextFilePath, "growx,span" );
JButton fileButton = new JButton( "File" );
fileButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final JFileChooser chooser = new JFileChooser();
int value = chooser.showOpenDialog( ScriptActionEditor.this );
if( value == JFileChooser.APPROVE_OPTION )
{
File file = chooser.getSelectedFile();
mTextFilePath.setText( file.getAbsolutePath() );
setModified( true );
}
}
} );
add( fileButton, "grow" );
JButton testButton = new JButton( "Test" );
testButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent actionEvent )
{
String script = mTextFilePath.getText();
if( script == null || script.trim().isEmpty() )
{
JOptionPane.showMessageDialog( ScriptActionEditor.this,
"Please select a script file", PLEASE_SELECT_A_FILE,
JOptionPane.ERROR_MESSAGE );
}
else
{
if( isModified() )
{
int option = JOptionPane.showConfirmDialog(
ScriptActionEditor.this,
"Settings have changed. Do you want to save these changes?",
"Save Changes?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE );
if( option == JOptionPane.YES_OPTION )
{
save();
}
}
new Thread( new Runnable()
{
@Override
public void run()
{
try
{
getScriptAction().play();
}
catch( Exception e1 )
{
JOptionPane.showMessageDialog( ScriptActionEditor.this,
e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
}
}
}).start();
}
}
} );
add( testButton, "grow,wrap" );
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( ScriptActionEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
@Override
public void setItem( AliasAction item )
{
super.setItem( item );
if( hasItem() )
{
ScriptAction script = getScriptAction();
RecurringAction.Interval interval = script.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != RecurringAction.Interval.ONCE;
mPeriodSliderLabel.setEnabled( enabled );
mPeriodSlider.setEnabled( enabled );
mPeriodSlider.setValue( script.getPeriod() );
String filepath = script.getScript();
if( filepath != null && !filepath.isEmpty() )
{
mTextFilePath.setText( filepath );
}
else
{
mTextFilePath.setText( PLEASE_SELECT_A_FILE );
}
}
setModified( false );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
ScriptAction script = getScriptAction();
script.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
script.setPeriod( mPeriodSlider.getValue() );
script.setScript( mTextFilePath.getText() );
}
setModified( false );
}
}

View File

@@ -1,20 +1,21 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias.id;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -22,47 +23,146 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.alias.id.dcs.Dcs;
import io.github.dsheirer.alias.id.esn.Esn;
import io.github.dsheirer.alias.id.fleetsync.FleetsyncID;
import io.github.dsheirer.alias.id.legacy.fleetsync.FleetsyncID;
import io.github.dsheirer.alias.id.legacy.mdc.MDC1200ID;
import io.github.dsheirer.alias.id.legacy.mobileID.Min;
import io.github.dsheirer.alias.id.legacy.mpt1327.MPT1327ID;
import io.github.dsheirer.alias.id.legacy.nonrecordable.NonRecordable;
import io.github.dsheirer.alias.id.legacy.siteID.SiteID;
import io.github.dsheirer.alias.id.legacy.talkgroup.LegacyTalkgroupID;
import io.github.dsheirer.alias.id.legacy.uniqueID.UniqueID;
import io.github.dsheirer.alias.id.lojack.LoJackFunctionAndID;
import io.github.dsheirer.alias.id.mdc.MDC1200ID;
import io.github.dsheirer.alias.id.mobileID.Min;
import io.github.dsheirer.alias.id.mpt1327.MPT1327ID;
import io.github.dsheirer.alias.id.nonrecordable.NonRecordable;
import io.github.dsheirer.alias.id.priority.Priority;
import io.github.dsheirer.alias.id.siteID.SiteID;
import io.github.dsheirer.alias.id.status.StatusID;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupID;
import io.github.dsheirer.alias.id.uniqueID.UniqueID;
import io.github.dsheirer.alias.id.radio.P25FullyQualifiedRadio;
import io.github.dsheirer.alias.id.radio.Radio;
import io.github.dsheirer.alias.id.radio.RadioRange;
import io.github.dsheirer.alias.id.record.Record;
import io.github.dsheirer.alias.id.status.UnitStatusID;
import io.github.dsheirer.alias.id.status.UserStatusID;
import io.github.dsheirer.alias.id.talkgroup.P25FullyQualifiedTalkgroup;
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
import io.github.dsheirer.alias.id.tone.TonesID;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.util.Callback;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.PROPERTY, property="type")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value=BroadcastChannel.class, name="broadcastChannel"),
@JsonSubTypes.Type(value=Esn.class, name="esn"),
@JsonSubTypes.Type(value=FleetsyncID.class, name="fleetsyncID"),
@JsonSubTypes.Type(value = BroadcastChannel.class, name = "broadcastChannel"),
@JsonSubTypes.Type(value = Dcs.class, name = "dcs"),
@JsonSubTypes.Type(value = Esn.class, name = "esn"),
@JsonSubTypes.Type(value = FleetsyncID.class, name = "fleetsyncID"),
@JsonSubTypes.Type(value = LegacyTalkgroupID.class, name = "talkgroupID"),
@JsonSubTypes.Type(value = LoJackFunctionAndID.class, name = "loJackFunctionAndID"),
@JsonSubTypes.Type(value = MDC1200ID.class, name = "mdc1200ID"),
@JsonSubTypes.Type(value = Min.class, name = "min"),
@JsonSubTypes.Type(value = MPT1327ID.class, name = "mpt1327ID"),
@JsonSubTypes.Type(value = NonRecordable.class, name = "nonRecordable"),
@JsonSubTypes.Type(value = P25FullyQualifiedRadio.class, name = "p25FullyQualifiedRadio"),
@JsonSubTypes.Type(value = P25FullyQualifiedTalkgroup.class, name = "p25FullyQualifiedTalkgroup"),
@JsonSubTypes.Type(value = Priority.class, name = "priority"),
@JsonSubTypes.Type(value = Radio.class, name = "radio"),
@JsonSubTypes.Type(value = RadioRange.class, name = "radioRange"),
@JsonSubTypes.Type(value = Record.class, name = "record"),
@JsonSubTypes.Type(value = SiteID.class, name = "siteID"),
@JsonSubTypes.Type(value = StatusID.class, name = "statusID"),
@JsonSubTypes.Type(value = TalkgroupID.class, name = "talkgroupID"),
@JsonSubTypes.Type(value = Talkgroup.class, name = "talkgroup"),
@JsonSubTypes.Type(value = TalkgroupRange.class, name = "talkgroupRange"),
@JsonSubTypes.Type(value = TonesID.class, name = "tones"),
@JsonSubTypes.Type(value = UserStatusID.class, name = "statusID"),
@JsonSubTypes.Type(value = UnitStatusID.class, name = "unitStatusID"),
@JsonSubTypes.Type(value = UniqueID.class, name = "uniqueID")
})
@JacksonXmlRootElement( localName = "id" )
@JacksonXmlRootElement(localName = "id")
public abstract class AliasID
{
public AliasID()
{
}
private SimpleStringProperty mValueProperty = new SimpleStringProperty();
private BooleanProperty mOverlapProperty = new SimpleBooleanProperty();
@JsonIgnore
public abstract AliasIDType getType();
public abstract boolean matches( AliasID id );
public AliasID()
{
}
@JsonIgnore
public abstract boolean isValid();
/**
* String property representation of this alias ID
*/
@JsonIgnore
public SimpleStringProperty valueProperty()
{
return mValueProperty;
}
/**
* Indicates if this alias identifier overlaps with any other alias identifier in the same alias list
*/
@JsonIgnore
public BooleanProperty overlapProperty()
{
return mOverlapProperty;
}
/**
* Sets the overlap flag for this alias id. Overlap indicates that this identifier collides with another
* identifier within the same alias list.
*/
public void setOverlap(boolean overlap)
{
mOverlapProperty.set(overlap);
updateValueProperty();
}
/**
* Updates the value property for this alias ID. Note: this method is intended to be invoked by all subclasses
* each time that any of the subclass member variable values change.
*/
public void updateValueProperty()
{
if(overlapProperty().get())
{
valueProperty().set(toString() + " - Error: Overlap");
}
else
{
valueProperty().set(toString());
}
//Hack: harmless, but the list extractor does not consistently update unless we do this.
valueProperty().get();
}
@JsonIgnore
public abstract AliasIDType getType();
public abstract boolean matches(AliasID id);
/**
* Indicates if this alias ID overlaps with another alias ID.
* Note: this method is intended to be overridden by certain subclass implementations.
*/
@JsonIgnore
public boolean overlaps(AliasID id)
{
return false;
}
@JsonIgnore
public abstract boolean isValid();
/**
* Indicates if the identifier is an audio identifier (monitor, record, stream)
*/
@JsonIgnore
public abstract boolean isAudioIdentifier();
/**
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
*/
public static Callback<AliasID,Observable[]> extractor()
{
return (AliasID aid) -> new Observable[] {aid.valueProperty(), aid.overlapProperty()};
}
}

View File

@@ -1,49 +1,67 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias.id;
import java.util.EnumSet;
public enum AliasIDType
{
ESN( "ESN" ),
FLEETSYNC( "Fleetsync" ),
LOJACK( "LoJack" ),
LTR_NET_UID( "LTR-Net UID" ),
MDC1200( "MDC-1200" ),
MIN( "Passport MIN" ),
MPT1327( "MPT-1327" ),
SITE( "Site" ),
STATUS( "Status" ),
TALKGROUP( "Talkgroup" ),
BROADCAST_CHANNEL("Audio Broadcast Channel"),
DCS("Digital Coded Squelch (DCS)"),
ESN("ESN"),
INVERT("Audio Inversion"),
LOJACK("LoJack"),
LTR_NET_UID("LTR-Net UID"),
MIN("Passport MIN"),
P25_FULLY_QUALIFIED_RADIO_ID("P25 Fully Qualified Radio ID"),
P25_FULLY_QUALIFIED_TALKGROUP("P25 Fully Qualified Talkgroup"),
PRIORITY("Audio Priority"),
RADIO_ID("Radio ID"),
RADIO_ID_RANGE("Radio ID Range"),
RECORD("Record"),
SITE("Site"),
STATUS("User Status"),
TONES("Tone Sequence"),
UNIT_STATUS("Unit Status"),
TALKGROUP("Talkgroup"),
TALKGROUP_RANGE("Talkgroup Range"),
INVERT( "Audio Inversion" ),
PRIORITY( "Audio Priority" ),
NON_RECORDABLE( "Audio Non-Recordable" ),
BROADCAST_CHANNEL( "Audio Broadcast Channel" );
private String mLabel;
private AliasIDType( String label )
{
mLabel = label;
}
public String toString()
{
return mLabel;
}
//Legacy identifier types - no longer used
FLEETSYNC("Fleetsync"),
LEGACY_TALKGROUP("Legacy Talkgroup"),
MDC1200("MDC-1200"),
MPT1327("MPT-1327"),
NON_RECORDABLE("Audio Non-Recordable");
private String mLabel;
AliasIDType(String label)
{
mLabel = label;
}
//Values used by the View-By alias editor
public static EnumSet<AliasIDType> VIEW_BY_VALUES = EnumSet.of(TALKGROUP, TALKGROUP_RANGE, RADIO_ID, RADIO_ID_RANGE,
P25_FULLY_QUALIFIED_RADIO_ID, P25_FULLY_QUALIFIED_TALKGROUP, UNIT_STATUS, STATUS, TONES);
public String toString()
{
return mLabel;
}
}

View File

@@ -1,367 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasEvent;
import io.github.dsheirer.alias.AliasFactory;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EmptyEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AliasIdentifierEditor extends Editor<Alias>
{
private static final long serialVersionUID = 1L;
private static ListModel<AliasID> EMPTY_MODEL = new DefaultListModel<>();
private JList<AliasID> mAliasIDList = new JList<>( EMPTY_MODEL );
private JButton mNewIDButton;
private JButton mCloneIDButton;
private JButton mDeleteIDButton;
private EditorContainer mEditorContainer = new EditorContainer();
private AliasModel mAliasModel;
private BroadcastModel mBroadcastModel;
public AliasIdentifierEditor( AliasModel aliasModel, BroadcastModel broadcastModel )
{
mAliasModel = aliasModel;
mBroadcastModel = broadcastModel;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 3",
"[grow,fill][grow,fill][grow,fill]", "[][grow,fill][]" ) );
mAliasIDList.setVisibleRowCount( 6 );
mAliasIDList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
mAliasIDList.setLayoutOrientation( JList.VERTICAL );
mAliasIDList.addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
JList<?> list = (JList<?>)event.getSource();
Object selectedItem = list.getSelectedValue();
if( selectedItem != null && selectedItem instanceof AliasID )
{
AliasID selected = (AliasID)selectedItem;
mEditorContainer.setAliasID( selected );
mCloneIDButton.setEnabled( true );
mDeleteIDButton.setEnabled( true );
}
else
{
mCloneIDButton.setEnabled( false );
mDeleteIDButton.setEnabled( false );
}
}
}
} );
JScrollPane scroller = new JScrollPane( mAliasIDList );
add( scroller, "span,grow" );
add( mEditorContainer, "span,grow" );
mNewIDButton = new JButton( "New ..." );
mNewIDButton.setToolTipText( "Create a new Alias Identifier" );
mNewIDButton.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JPopupMenu menu = new JPopupMenu();
menu.add( new AddAliasIdentifierItem( AliasIDType.ESN ) );
menu.add( new AddAliasIdentifierItem( AliasIDType.FLEETSYNC) );
menu.add( new AddAliasIdentifierItem( AliasIDType.LOJACK) );
menu.add( new AddAliasIdentifierItem( AliasIDType.LTR_NET_UID) );
menu.add( new AddAliasIdentifierItem( AliasIDType.MDC1200 ) );
menu.add( new AddAliasIdentifierItem( AliasIDType.MPT1327 ) );
menu.add( new AddAliasIdentifierItem( AliasIDType.MIN ) );
menu.add( new AddAliasIdentifierItem( AliasIDType.SITE) );
menu.add( new AddAliasIdentifierItem( AliasIDType.STATUS) );
menu.add( new AddAliasIdentifierItem( AliasIDType.TALKGROUP) );
menu.addSeparator();
menu.add( new AddAliasIdentifierItem( AliasIDType.BROADCAST_CHANNEL) );
if( hasItem() )
{
Alias alias = getItem();
if( alias.isRecordable() )
{
menu.add( new AddAliasIdentifierItem( AliasIDType.NON_RECORDABLE) );
}
if( !alias.hasCallPriority() )
{
menu.add( new AddAliasIdentifierItem( AliasIDType.PRIORITY) );
}
}
menu.show( e.getComponent(), e.getX(), e.getY() );
}
} );
add( mNewIDButton );
mCloneIDButton = new JButton( "Clone" );
mCloneIDButton.setToolTipText( "Create a copy of the currently selected identifier" );
mCloneIDButton.setEnabled( false );
mCloneIDButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
AliasID selected = mAliasIDList.getSelectedValue();
if( selected != null )
{
AliasID clone = AliasFactory.copyOf( selected );
if( clone != null )
{
addAliasIDToList( clone );
}
}
}
} );
add( mCloneIDButton );
mDeleteIDButton = new JButton( "Delete" );
mDeleteIDButton.setToolTipText( "Delete the currently selected identifier" );
mDeleteIDButton.setEnabled( false );
mDeleteIDButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final AliasID selected = mAliasIDList.getSelectedValue();
if( selected != null )
{
int choice = JOptionPane.showConfirmDialog( mDeleteIDButton,
"Do you want to delete [" + selected.toString() + "]",
"Are you sure?", JOptionPane.YES_NO_OPTION );
if( choice == JOptionPane.YES_OPTION && hasItem() )
{
Alias alias = getItem();
alias.removeAliasID( selected );
mAliasModel.broadcast( new AliasEvent( alias, AliasEvent.Event.CHANGE ) );
setItem( alias );
}
}
}
} );
add( mDeleteIDButton, "wrap" );
}
@Override
public void setItem( Alias alias )
{
super.setItem( alias );
if( alias == null || alias.getId().isEmpty() )
{
mAliasIDList.setModel( EMPTY_MODEL );
}
else
{
DefaultListModel<AliasID> model = new DefaultListModel<AliasID>();
List<AliasID> ids = alias.getId();
Collections.sort( ids, new Comparator<AliasID>()
{
@Override
public int compare( AliasID o1, AliasID o2 )
{
return o1.toString().compareTo( o2.toString() );
}
} );
for( AliasID id: ids )
{
model.addElement( id );
}
mAliasIDList.setModel( model );
}
mEditorContainer.setAliasID( null );
}
@Override
public void save()
{
if( isModified() || mEditorContainer.isModified() )
{
if( mEditorContainer.isModified() )
{
mEditorContainer.save();
}
setModified( false );
if( hasItem() )
{
mAliasModel.broadcast( new AliasEvent( getItem(), AliasEvent.Event.CHANGE ) );
}
}
}
public class EditorContainer extends JPanel
{
private static final long serialVersionUID = 1L;
private Editor<AliasID> mEditor = new EmptyEditor<>();
public EditorContainer()
{
setLayout( new MigLayout( "","[grow,fill]", "[grow,fill]" ) );
add( mEditor );
}
public boolean isModified()
{
if( mEditor != null )
{
return mEditor.isModified();
}
return false;
}
public void save()
{
if( mEditor != null )
{
mEditor.save();
}
}
public void setAliasID( AliasID aliasID )
{
if( mEditor != null )
{
if( mEditor.isModified() )
{
int option = JOptionPane.showConfirmDialog(
EditorContainer.this,
"Identifier settings have changed. Do you want to save these changes?",
"Save Changes?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE );
if( option == JOptionPane.YES_OPTION )
{
mEditor.save();
}
}
}
removeAll();
//This will always give us an editor
mEditor = AliasFactory.getEditor( aliasID, mBroadcastModel );
add( mEditor );
revalidate();
}
}
private void addAliasIDToList( final AliasID id )
{
if( id != null && hasItem() )
{
final Alias alias = getItem();
alias.addAliasID( id );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
setItem( alias );
mAliasIDList.setSelectedValue( id, true );
AliasIdentifierEditor.this.setModified( true );
}
} );
}
}
public class AddAliasIdentifierItem extends JMenuItem
{
private static final long serialVersionUID = 1L;
private AliasIDType mAliasIDType;
public AddAliasIdentifierItem( AliasIDType type )
{
super( type.toString() );
mAliasIDType = type;
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final AliasID id = AliasFactory.getAliasID( mAliasIDType );
addAliasIDToList( id );
}
} );
}
}
}

View File

@@ -1,113 +0,0 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.alias.id;
import org.apache.commons.lang3.Validate;
import java.util.regex.Pattern;
public class WildcardID implements Comparable<WildcardID>
{
public static final String WILDCARD = "*";
public static final String REGEX_WILDCARD = ".";
private String mValue;
private Pattern mPattern;
private int mWeight;
/**
* Wildcard identifier for matching to string identifiers containing single-character (*) wildcard values.
*
* Supports ordering from most-specific to least-specific using the build-in weighting calculation where identifier
* patterns containing fewer wildcards closer to the least significant digit will be weighted more heavily than
* identifier patterns containing more wildcards, or wildcard characters in the most significant digits.
*
* @param value is a string value containing one or more asterisk (*) single character wildcard with a maximum
* length of 10 characters.
*
* @throws AssertionError if the value is null, longer than 10 characters, or doesn't contain at least 1 asterisk
* @throws IllegalArgumentException if the value cannot be compiled as a regular expression after converting the
* asterisk characters to the regex single-character wildcard value (.)
*/
public WildcardID(String value)
{
Validate.isTrue(value != null && value.contains(WILDCARD) && value.length() < 10);
mValue = value;
try
{
mPattern = Pattern.compile(value.replace(WILDCARD, REGEX_WILDCARD));
}
catch(Exception e)
{
throw new IllegalArgumentException("Invalid regex pattern for alias ID value [" + value + "]", e);
}
mWeight = calculateWeight();
}
public String value()
{
return mValue;
}
/**
* Indicates if the id matches the internal regex pattern for this wildcard alias ID
* @param id
* @return
*/
public boolean matches(String id)
{
return id != null && mPattern.matcher(id).matches();
}
public int weight()
{
return mWeight;
}
/**
* Calculates a weighting value for wildcard character quantity and significant digit location
*/
private int calculateWeight()
{
int weight = 0;
int characterCount = -1;
for( int x = 0; x < mValue.length(); x++)
{
if(mValue.substring(x, x + 1).equals(WILDCARD))
{
weight += (int)(Math.pow(2, mValue.length() - x - 1)); //Position weight
characterCount++;
}
}
weight += (int)(Math.pow(2, characterCount)) * 1000; //Character count weight
return weight;
}
@Override
public int compareTo(WildcardID otherWildcardID)
{
return Integer.compare(this.weight(), otherWildcardID.weight());
}
}

View File

@@ -1,21 +1,24 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
*/
package io.github.dsheirer.alias.id.broadcast;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -31,6 +34,12 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
//JAXB Constructor
}
@Override
public boolean isAudioIdentifier()
{
return true;
}
@Override
public int compareTo(BroadcastChannel other)
{
@@ -94,6 +103,7 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
public void setChannelName(String channel)
{
mChannelName = channel;
updateValueProperty();
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@@ -118,13 +128,6 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
@Override
public String toString()
{
if(isValid())
{
return "Broadcast Channel: " + mChannelName;
}
else
{
return "Broadcast Channel: None Selected";
}
return isValid() ? mChannelName : "(invalid)";
}
}

View File

@@ -1,129 +0,0 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.alias.id.broadcast;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
public class BroadcastChannelEditor extends DocumentListenerEditor<AliasID>
{
private static final long serialVersionUID = 1L;
private static final String HELP_TEXT = "<html>"
+ "<h3>Audio Broadcast Channel</h3>"
+ "Name of a audio streaming broadcast configuration<br>"
+ "to be used for streaming audio to an external<br>"
+ "streaming server";
private JComboBox<String> mBroadcastConfigurations;
private BroadcastModel mBroadcastModel;
public BroadcastChannelEditor(AliasID aliasID, BroadcastModel broadcastModel)
{
mBroadcastModel = broadcastModel;
initGUI();
setItem( aliasID );
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 1", "[]", "[][]" ) );
add( new JLabel( "Broadcast Channel" ), "grow" );
List<String> channelNames = mBroadcastModel.getBroadcastConfigurationNames();
mBroadcastConfigurations = new JComboBox<String>(channelNames.toArray(new String[channelNames.size()]));
mBroadcastConfigurations.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mBroadcastConfigurations, "grow");
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( BroadcastChannelEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
@Override
public void setItem(AliasID item)
{
super.setItem(item);
if(item instanceof BroadcastChannel)
{
BroadcastChannel channel = (BroadcastChannel)item;
if(channel.isValid())
{
mBroadcastConfigurations.setSelectedItem(channel.getChannelName());
}
}
setModified(false);
}
@Override
public void save()
{
String channel = (String)mBroadcastConfigurations.getSelectedItem();
BroadcastConfiguration selectedConfiguration = mBroadcastModel.getBroadcastConfiguration(channel);
if(selectedConfiguration != null)
{
((BroadcastChannel)getItem()).setChannelName(selectedConfiguration.getName());
}
else
{
((BroadcastChannel)getItem()).setChannelName(null);
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.alias.id.dcs;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.module.decode.dcs.DCSCode;
/**
* Digital Coded Squelch (DCS) tone identifier
*/
public class Dcs extends AliasID implements Comparable<Dcs>
{
private DCSCode mDCSCode;
@Override
public AliasIDType getType()
{
return AliasIDType.DCS;
}
@Override
public boolean matches(AliasID id)
{
if(isValid() && id instanceof Dcs other)
{
return other.isValid() && getDCSCode().equals(other.getDCSCode());
}
return false;
}
/**
* DCS code
* @return DCS code or null.
*/
@JacksonXmlProperty(isAttribute = true, localName = "code")
public DCSCode getDCSCode()
{
return mDCSCode;
}
/**
* Sets the DCS code value.
* @param dcsCode to set
*/
public void setDCSCode(DCSCode dcsCode)
{
mDCSCode = dcsCode;
updateValueProperty();
}
@Override
public boolean isValid()
{
return mDCSCode != null;
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@Override
public String toString()
{
if(isValid())
{
return getDCSCode().toString();
}
return "DCS-Invalid - No Tone Selected";
}
@Override
public int compareTo(Dcs o)
{
if(isValid())
{
if(o.isValid())
{
return getDCSCode().compareTo(o.getDCSCode());
}
else
{
return 1;
}
}
return -1;
}
}

View File

@@ -1,113 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.esn;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ESNEditor extends DocumentListenerEditor<AliasID>
{
private static final long serialVersionUID = 1L;
private static final String HELP_TEXT =
"<html><h3>Electronic Serial Number (ESN)</h3>"
+ "<b>ESN:</b> hexadecimal 0-9, A-F (e.g. <u>ABCD1234</u> )<br>"
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard individual<br>"
+ "digits (e.g. <u>ABCD123*</u> or <u>AB**1**4</u>)"
+ "</html>";
private JTextField mTextField;
public ESNEditor( AliasID aliasID )
{
initGUI();
setItem( aliasID );
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
add( new JLabel( "ESN:" ) );
mTextField = new JTextField();
mTextField.getDocument().addDocumentListener( this );
mTextField.setToolTipText( HELP_TEXT );
add( mTextField, "growx,push" );
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( ESNEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
public Esn getEsn()
{
if( getItem() instanceof Esn )
{
return (Esn)getItem();
}
return null;
}
@Override
public void setItem( AliasID aliasID )
{
super.setItem( aliasID );
Esn esn = getEsn();
if( esn != null )
{
mTextField.setText( esn.getEsn() );
}
setModified( false );
repaint();
}
@Override
public void save()
{
Esn esn = getEsn();
if( esn != null )
{
esn.setEsn( mTextField.getText() );
}
setModified( false );
}
}

View File

@@ -29,6 +29,12 @@ public class Esn extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "esn")
public String getEsn()
{
@@ -44,11 +50,18 @@ public class Esn extends AliasID
public void setEsn(String esn )
{
mEsn = esn;
updateValueProperty();
}
public String toString()
{
return "ESN: " + mEsn;
StringBuilder sb = new StringBuilder();
sb.append("ESN: ").append(mEsn != null ? mEsn : "(empty)");
if(!isValid())
{
sb.append(" **NOT VALID**");
}
return sb.toString();
}
@Override

View File

@@ -1,131 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.fleetsync;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class FleetsyncIDEditor extends DocumentListenerEditor<AliasID>
{
private final static Logger mLog = LoggerFactory.getLogger( FleetsyncIDEditor.class );
private static final long serialVersionUID = 1L;
private static final String HELP_TEXT = "<html>"
+ "<h3>Fleetsync Identifier</h3>"
+ "<b>Fleetsync:</b> ggg-uuuu where g=Group and u=Unit (e.g. <u>001-0001</u>)<br>"
+ "<b>Wildcard:</b> use an asterisk (*) for each digit (e.g. <u>001-****</u>)"
+ "</html>";
private JTextField mTextField;
public FleetsyncIDEditor( AliasID aliasID )
{
initGUI();
setItem( aliasID );
}
private void initGUI()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
add( new JLabel( "Fleetsync ID:" ) );
MaskFormatter formatter = null;
try
{
//Mask: 3 digits - 4 digits
formatter = new MaskFormatter( "###-####" );
}
catch( Exception e )
{
//Do nothing, the mask was invalid
}
mTextField = new JFormattedTextField( formatter );
mTextField.getDocument().addDocumentListener( this );
mTextField.setToolTipText( HELP_TEXT );
add( mTextField, "growx,push" );
JLabel help = new JLabel( "Help ..." );
help.setForeground( Color.BLUE.brighter() );
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
help.addMouseListener( new MouseAdapter()
{
@Override
public void mouseClicked( MouseEvent e )
{
JOptionPane.showMessageDialog( FleetsyncIDEditor.this,
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
}
} );
add( help, "align left" );
}
public FleetsyncID getFleetsyncID()
{
if( getItem() instanceof FleetsyncID )
{
return (FleetsyncID)getItem();
}
return null;
}
@Override
public void setItem( AliasID aliasID )
{
super.setItem( aliasID );
FleetsyncID fleetsync = getFleetsyncID();
if( fleetsync != null )
{
mTextField.setText( fleetsync.getIdent() );
}
setModified( false );
repaint();
}
@Override
public void save()
{
FleetsyncID fleetsync = getFleetsyncID();
if( fleetsync != null )
{
fleetsync.setIdent( mTextField.getText() );
}
setModified( false );
}
}

View File

@@ -1,21 +1,23 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.fleetsync;
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.id.legacy.fleetsync;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.id.AliasID;
@@ -29,6 +31,12 @@ public class FleetsyncID extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "ident")
public String getIdent()
{
@@ -48,7 +56,7 @@ public class FleetsyncID extends AliasID
public String toString()
{
return "Fleetsync: " + mID;
return "Fleetsync: " + (mID != null ? mID : "(empty)") + " **INVALID - USE TALKGROUP INSTEAD";
}
@Override

View File

@@ -1,21 +1,23 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.mdc;
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.id.legacy.mdc;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -30,6 +32,12 @@ public class MDC1200ID extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "ident")
public String getIdent()
{
@@ -49,7 +57,7 @@ public class MDC1200ID extends AliasID
public String toString()
{
return "MDC-1200: " + mID;
return "MDC-1200: " + (mID != null ? mID : "(empty)") + " **INVALID - USE TALKGROUP INSTEAD**";
}
@Override

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.mobileID;
package io.github.dsheirer.alias.id.legacy.mobileID;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -33,6 +33,12 @@ public class Min extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "min")
public String getMin()
{
@@ -52,7 +58,7 @@ public class Min extends AliasID
public String toString()
{
return "MIN: " + mMin;
return "MIN: " + (mMin != null ? mMin : "(empty)") + (isValid() ? "" : " **INVALID - USE TALKGROUP INSTEAD");
}
@Override

View File

@@ -1,21 +1,23 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.mpt1327;
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.id.legacy.mpt1327;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -30,6 +32,12 @@ public class MPT1327ID extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "ident")
public String getIdent()
{
@@ -49,7 +57,7 @@ public class MPT1327ID extends AliasID
public String toString()
{
return "MPT-1327: " + mID;
return "MPT-1327: " + (mID != null ? mID : "(empty)") + " **INVALID - USE TALKGROUP INSTEAD**";
}
@Override

View File

@@ -0,0 +1,59 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.id.legacy.nonrecordable;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
public class NonRecordable extends AliasID
{
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@Override
public AliasIDType getType()
{
return AliasIDType.NON_RECORDABLE;
}
@Override
public boolean isAudioIdentifier()
{
return true;
}
@Override
public boolean isValid()
{
return true;
}
@Override
public boolean matches(AliasID id)
{
return false;
}
@Override
public String toString()
{
return "Audio Non-Recordable - **INVALID - USE RECORD INSTEAD**";
}
}

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.alias.id.siteID;
package io.github.dsheirer.alias.id.legacy.siteID;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.id.AliasID;
@@ -29,6 +29,12 @@ public class SiteID extends AliasID
{
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "site")
public String getSite()
{
@@ -48,7 +54,7 @@ public class SiteID extends AliasID
public String toString()
{
return "Site: " + mSite;
return "Site: " + (mSite != null ? mSite : "(empty)") + (isValid() ? "" : " **NOT VALID**");
}
@Override

View File

@@ -0,0 +1,97 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.alias.id.legacy.talkgroup;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
public class LegacyTalkgroupID extends AliasID
{
private String mTalkgroup;
public LegacyTalkgroupID()
{
//No arg JAXB constructor
}
public LegacyTalkgroupID(String talkgroup)
{
mTalkgroup = talkgroup;
}
@Override
public boolean isAudioIdentifier()
{
return false;
}
@JacksonXmlProperty(isAttribute = true, localName = "talkgroup")
public String getTalkgroup()
{
return mTalkgroup;
}
public void setTalkgroup(String talkgroup)
{
mTalkgroup = talkgroup;
}
@Override
public boolean isValid()
{
return mTalkgroup != null;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Legacy Talkgroup:").append(mTalkgroup).append(" *Disabled - Please use Talkgroup instead");
return sb.toString();
}
@Override
public boolean matches(AliasID id)
{
boolean retVal = false;
if(id instanceof LegacyTalkgroupID)
{
LegacyTalkgroupID tgid = (LegacyTalkgroupID)id;
//Create a pattern - replace * wildcards with regex single-char wildcard
String pattern = mTalkgroup.replace("*", ".?");
retVal = tgid.getTalkgroup().matches(pattern);
}
return retVal;
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
@Override
public AliasIDType getType()
{
return AliasIDType.LEGACY_TALKGROUP;
}
}

Some files were not shown because too many files have changed in this diff Show More