Compare commits

...

442 Commits

Author SHA1 Message Date
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
Denny
bb0bcd3198 Updates build to 0.4.0 alpha 3 2018-09-05 07:34:09 -04:00
Denny Sheirer
cb54850f99 Merge pull request #402 from DSheirer/heterodyne_channelizer
401 Update Tuners to use Heterodyne Channelizer
2018-09-05 07:31:57 -04:00
Denny
5bb8c46bd5 Merge remote-tracking branch 'origin/heterodyne_channelizer' into heterodyne_channelizer 2018-09-05 07:27:39 -04:00
Denny
2a3fd2c5a3 Class renaming and cleanup. 2018-09-05 07:27:18 -04:00
Denny
d712feb45a Class renaming and cleanup. 2018-09-05 07:26:52 -04:00
Denny
fbb24a4c05 Class renaming and cleanup. 2018-09-05 07:24:42 -04:00
Denny
3992f8178c Merge remote-tracking branch 'origin/heterodyne_channelizer' into heterodyne_channelizer
# Conflicts:
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
2018-09-05 07:19:37 -04:00
Denny
8642def77e Cleanup, renaming and removing legacy code. 2018-09-05 07:17:51 -04:00
Denny
38e6de6cb2 Resolves cutoff frequency for 2 channel polyphase synthesizer. 2018-09-05 07:17:51 -04:00
Denny
994e78f42b Resolves issue with polyphase filter gain and channel output processor gain 2018-09-05 07:16:51 -04:00
Denny
b8a46af836 Creates new HeterodyneChannelSourceManager that uses frequency translation
and CIC decimation for each channel provided by the tuner.
2018-09-05 07:15:57 -04:00
Denny
1c6d19959a Class renaming and cleanup. 2018-09-05 06:34:13 -04:00
Denny
50bc3088b7 Removes unused legacy code. 2018-09-05 06:31:39 -04:00
Denny
09356848eb Merge branch 'master' into heterodyne_channelizer
# Conflicts:
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
2018-09-05 06:18:27 -04:00
Denny Sheirer
316bfb19c2 Merge pull request #400 from DSheirer/375-channelizer-synthesizer-gain-issue
375 channelizer synthesizer gain issue
2018-09-05 06:17:47 -04:00
Denny
c045c8f16d Updates heterodyne channel manager to correctly lock/unlock the tuner
controller.
2018-09-05 06:11:28 -04:00
Denny
8946d789ff WIP - updated tuners to use CIC decimation tuner channel sources instead
of polyphase channelizer.

Channel sample rate reduced to 30 kHz - seems to work better with P25
decoders than previous 25 kHz.
2018-09-04 08:16:57 -04:00
Denny
19399d9138 Resolves cutoff frequency for 2 channel polyphase synthesizer. 2018-09-01 06:32:24 -04:00
Denny
9acdf22b91 WIP - identifier framework and restructuring P25 messages to provide
identifiers.
2018-08-31 04:50:58 -04:00
Denny Sheirer
f963d821a1 Merge pull request #396 from DSheirer/394-p25-bitstream-output
394 P25 bit stream output
2018-08-18 03:52:36 -04:00
Denny
ade0cef50b Updates P25 C4FM and LSM decoders to provide demodulated bit streams
for recording using the new binary recorders/format.
2018-08-18 03:36:17 -04:00
Denny
2044c2a2de WIP - Updated P25 C4FM and LSM decoders to assemble dibits and push
reusable byte buffers out to the processing chain.  This enables the
processing chain to broadcast these buffers back to the decoder for
message assembly and to any running binary recorder.

Updated P25Decoder to be a reusable byte buffer listener.  The decoder
will now pass reusable byte buffers down to the message framer for
message processing.  This should make the code more efficient since it
can process byte arrays versus handling each individual dibit.

The P25MessageFramer has been updated to be a listener of reusable byte
buffers instead of Dibits, but the actual processing of byte arrays
has to be coded.

Added max recording size to the binary recorder so that it cycles at
500 kB max file size.
2018-08-17 07:27:04 -04:00
Denny Sheirer
1c312a50b6 Merge pull request #395 from DSheirer/393-raw-bitstream-recording
393 Recording raw decoded bitstream from supported decoder types
2018-08-11 08:09:22 -04:00
Denny
54f6bd09e2 Cleanup 2018-08-11 08:08:57 -04:00
Denny
5f8f2ec330 Resolves #393 - Adds support for recording demodulated (raw) bitstream
buffers.  None of the decoders currently support this yet, but the P25
will be updated to provide bitstream output for recording.

Renames the ReusableBuffer class to ReusableFloatBuffer for
consistency.
2018-08-11 08:02:58 -04:00
Denny Sheirer
d7e018f66e Merge pull request #392 from DSheirer/390-polyphase-channel-source-npe
390 PolyphaseChannelSource NPE
2018-08-11 05:43:35 -04:00
Denny
c2a232fdee Adds null checking to output processor. 2018-08-11 05:42:45 -04:00
Denny Sheirer
c5d2dcd0cf Merge pull request #391 from DSheirer/389-add-active-to-channel-states
389 Add ACTIVE Channel State and Update P25 Decoder State processing
2018-08-11 05:39:20 -04:00
Denny
8e4e4129ca Adds 'ACTIVE' as a valid channel state to indicate that the channel is
actively decoding, but no call or data is being transmitted.  This is
primarily used for P25 channels when TDU Link Control messages are
being transmitted in between voice or data transmissions on a channel.

Updated several of the P25 decoder state message processing sections to
keep the channel state UI updated with current call identifiers and
states.

Hard-coded channel state colors to remove inefficiency in the way that
channel state coloration was being handled.
2018-08-11 05:36:30 -04:00
Denny
9176ca610f Updates build to Version 0.4.0 Alpha 2 2018-08-05 07:51:40 -04:00
Denny Sheirer
97b31e4d9b Merge pull request #385 from DSheirer/372-icecast-streaming-reconnect
372 Icecast Streaming Reconnect and Metadata Updates
2018-08-05 07:48:28 -04:00
Denny
a3e5520d3e Resolves #372 - Icecast reconnect following network outage. Updates
the lost connection timeout from default of 60 seconds down to 5 seconds
so that the connection state updates more quickly.  Removed complex
error handling and replaced with a simpler approach to catch an error
and disconnect and then attempt a reconnect.

Added new 'Network Unavailable' error state that detects when the network
connection is unavaialable.

Updated the icecast metadata updater to close the TCP session after
successfully writing metadata to the socket.
2018-08-05 07:44:46 -04:00
Denny
8c456972cc Decreases usable bandwidth of the R820T tuner to 98% so that channels
do not get allocated at the spectral extremes where the signal is
degraded.
2018-08-03 11:02:47 -04:00
Denny
35d81ab31d Decreases buffer size for low sample rates for RTL2832 tuners. 2018-08-03 08:06:00 -04:00
Denny
b90b06e600 Merge remote-tracking branch 'origin/master' 2018-08-03 07:57:58 -04:00
Denny
04144ca677 Adds additional RTL 2832 sample rate options 2018-08-03 07:57:47 -04:00
Denny Sheirer
d3c7a50918 Merge pull request #384 from DSheirer/382-rtl-tuner-sample-rate-options
382 - Additional Sample Rate Options for RTL2832 Tuners
2018-08-03 07:53:01 -04:00
Denny
0fd29fa35a Resolves #382 - Adds additional sample rate options for the RTL2832
tuner and adjusts the low sample rate buffer size down to 16 kb.
2018-08-03 07:50:36 -04:00
Denny Sheirer
c00b173064 Merge pull request #383 from DSheirer/381-rtl-tuner-adaptive-native-buffer-size
381 Adaptive USB Transfer Buffer Sizes for RTL2832 Tuners
2018-08-03 07:29:31 -04:00
Denny
2718367259 Resolves #381. Updates USB transfer processor to use native transfer
buffer sizes that adapt to the selected sample rate.
2018-08-03 07:27:58 -04:00
Denny Sheirer
3f0c13096a Merge pull request #380 from DSheirer/374-rtl-tuner-sample-rate-issue
374 RTL Tuner Sample Rates Not Supported (1.44 & 2.88 MHz)
2018-08-03 07:04:28 -04:00
Denny
71ba4adbd7 Resolves #374
Updates polyphase channel manager to correctly calculate the number of
channels for each sample rate change.
2018-08-03 07:02:58 -04:00
Denny Sheirer
3908e29a2e Merge pull request #376 from DSheirer/373-tuner-ppm-monitoring-and-adjustment
#373 - Tuner PPM Error Monitoring and R820T PPM Auto-Correction
2018-07-29 11:18:47 -04:00
Denny
0c47efea03 Resolves #373 - Adds support for Tuner frequency error PPM monitoring
and auto-correction for R820T tuners.

-Updated TunerModel and TunerViewPanel to add 2 new columns to
display the current tuner's PPM setting and (when available) the
measured frequency error averaged over 5 second intervals provided by
certain decoders (e.g. P25 C4FM and LSM).  Frequency error value from
P25 decoders is provided from the Costas Loop PLL once 2 or more P25
message sync events have been observed in a short period.
-Updated R820T tuner to auto-correct PPM when measured frequency error
exceeds the +/- 0.4PPM threshold for a period of 30 seconds or more.
Feature can be enabled/disabled by user in the tuner editor panel.

Resolved several issues with P25 C4FM/LSM decoders that was impacting
performance related to channel misalignment from tuner PPM offsets.
2018-07-29 10:48:29 -04:00
Denny
5c0d97d942 Resolves issue with array out of bounds exception on shutdown while
removing tuners from the tuner model.
2018-07-20 05:59:00 -04:00
Denny
61ae0d2d83 Resolves issue with saved setting for spectral display panel enabled state 2018-07-20 05:58:23 -04:00
Denny Sheirer
68f2a8da2c Merge pull request #371 from DSheirer/370-tuner-editor-lock-state
Resolved #370 Tuner Editor Lock State
2018-07-15 05:55:46 -04:00
Denny
0d69f11e65 Resolved #370 Tuner Editor Lock State
Resolves an issue with the previous implementation where the tuner
editor was being refreshed repeatedly to update the lock state for the
tuner, rendering the editor almost completely unusable.

Now updates only the frequency control and the sample rate control to
reflect the tuner's lock state.
2018-07-15 05:55:28 -04:00
Denny Sheirer
b3d5daea8b Merge pull request #369 from DSheirer/320-mixer-gain-r820t-tuner
360 R820T Mixer Gain Labels
2018-07-15 05:30:45 -04:00
Denny
fe34623c4a Resolves #320
Changes labels for R820T mixer gain settings.
2018-07-15 05:29:21 -04:00
Denny Sheirer
353747cecc Merge pull request #368 from DSheirer/96-disable-spectral-display-option
#96 Disable Spectral Display Option
2018-07-14 16:05:00 -04:00
Denny
a8c649ef64 Resolves #96
Adds capability to disable spectral display.

Adds right-click context
menu items to disable display and/or reenable display by selecting
another tuner.

Adds view menu items to disable spectral display or show a tuner.

Persists spectral display enabled state across application run sessions.
2018-07-14 16:04:18 -04:00
Denny Sheirer
8cf50e629e Merge pull request #367 from DSheirer/366-application-shutdown
366 Application Shutdown Procedure
2018-07-14 14:45:00 -04:00
Denny
20a8f2bb3c Fully implements application shutdown procedure that is invoked when the
user closes the the main gui window or invokes exit from the file menu.
2018-07-14 14:44:03 -04:00
Denny
8c237be682 Resolves issue with Mute/Unmute icon rendering. 2018-07-14 13:39:43 -04:00
Denny Sheirer
2d5271b849 Merge pull request #365 from DSheirer/364-p25-pll-lock-gain
#364 Excessive P25 PLL Sync Lock Timelines
2018-07-14 11:29:18 -04:00
Denny
609a1e86c7 Resolves #364.
The C4FM and LSM decoders were issuing a PLL reset with each new
channel that was allocated, causing any existing decoding channels to
be disrupted.  Decoding re-sync delays or inability to recapture the
 signal for decoding would likely result as the tuner's overall PPM
 caused misadjustment in the channel.

Resolved a NPE that was occurring in the FrequencyController for
sample rate changes.
2018-07-14 11:27:38 -04:00
Denny Sheirer
821e719015 Merge pull request #363 from DSheirer/170-airspy-mini-sample-rates
#170 Add Support for Airspy Mini tuner's 3 and 6 MHz
2018-07-14 07:47:03 -04:00
Denny
104c4f72be Resolves #170 adding support for Airspy Mini tuner's 3 and 6 MHz
sample rates.

Resolves issue in PolyphaseChannelManager responding to sample rate
changes in the tuner.  The manager now recreates the channelizer when
needed if the tuner's sample rate has changed since the last time the
channelizer was used.

Updates the Tuner selection view to reflect tuner lock state.  Updates
the tuner editors to enable/disable frequency controller and sample
rate controls according to the tuner's lock state.
2018-07-14 07:45:42 -04:00
Denny
9e7fa7618d Logging cleanup. 2018-07-04 06:05:15 -04:00
Denny
ee09520181 Updates build script to version 0.4.0 alpha 1. Adds missing resampler
library.
2018-07-01 20:52:38 -04:00
Denny Sheirer
fa12b840db Merge pull request #357 from DSheirer/39-polyphase-channelizer
39 polyphase channelizer and decoder updates
2018-07-01 07:30:06 -04:00
Denny
183d7d6d19 Logging cleanup 2018-07-01 07:25:37 -04:00
Denny
e2550869ce Disables debug logging of reusable buffer creation. 2018-07-01 07:21:42 -04:00
Denny
e88944e53d Updates all reusable buffer queues to automatically set the user count
to 1 on all provided buffers by default.
2018-07-01 07:08:52 -04:00
Denny
0051a1d381 Removes debug logging for polyphase channelizer and reusable buffer queues. 2018-07-01 06:43:40 -04:00
Denny
f7a873dd0c Removes AFC settings from all decode configurations. 2018-07-01 05:43:42 -04:00
Denny
ad560db5ea [WIP] Removes all usage of Buffer, RealBuffer and ComplexBuffer. 2018-06-30 06:54:36 -04:00
Denny
6f1ce79461 [WIP] Updates the AM decoder module.
Removes a number of unused classes in an effort to remove RealBuffer
usage across the codebase (has been replaced by ReusableBuffers).
2018-06-30 05:37:13 -04:00
Denny
df1bc1031e [WIP] Updates AudioPackets to be ReusableAudioPackets. 2018-06-29 06:53:03 -04:00
Denny
a621a31aa9 [WIP] Updates the sample adapters to natively use ReusableBuffers.
Refactors a MixerReader instance from the RealMixerSource so that it
can be reused for both real and complex data outputs.

Updates RealMixerSource to use refactored MixerReader and use a default
sample rate of 8 kHz.

Updates the ComplexMixer to use the refactored MixerReader.

Updates the FCD 1/2 tuners for compatibility with the new ComplexMixer.

Removes several unused classes.
2018-06-24 09:50:36 -04:00
Denny
19fa256c60 [WIP]Updates mixer manager and mixer source to use 8 kHz audio for
sound card inputs.

Updated DecoderFactory to only include an AM/FM demodulator when we're
using a tuner input.
2018-06-23 09:49:40 -04:00
Denny
7a830077bd [WIP] Cleanup. Refactors DecoderFX application to the gui package. 2018-06-15 07:29:27 -04:00
Denny
f4793f3cfd [WIP] Cleanup. Removes the legacy Instrumentable, Taps, etc and related
gui components.  Refactors the new DecoderFX application to the
instrument package.
2018-06-15 07:27:17 -04:00
Denny
2cd3b73633 [WIP]Updates the MDC1200 decoder to use the new AFSK1200 decoder
class.

Adds Demodulator Viewer FX pane for MDC1200 decoder.
2018-06-15 07:11:07 -04:00
Denny
18f50485d3 [WIP]Updates the Tait1200 decoder to use the new AFSK1200 decoder
class.

Adds Demodulator Viewer FX pane for Tait1200 decoder.
2018-06-15 06:56:44 -04:00
Denny
b410cf0dfe [WIP]Updates the LJ-1200 decoder to use the new AFSK1200 decoder
class.

Adds Demodulator Viewer FX panes for MPT-1327 and LJ-1200 decoders.
2018-06-15 06:19:50 -04:00
Denny
1fdcb623a6 [WIP]Updates the MPT-1327 decoder to use the new AFSK1200 decoder
class.
2018-06-11 04:32:30 -04:00
Denny
9dda1f95a1 [WIP] Creates a new AFSK-1200 correlation decoder and updates the
Fleetsync II decoder to use it.  Adds instrumented version of the decoder
and a new Fleetsync2 FX pane to the DemodulatorViewerFX tool.

Note: the remaining AFSK-1200 based decoders will all be ported to use
this new AFSK1200 decoder (MDC1200, Tait1200, LowJack1200).
2018-06-09 08:17:18 -04:00
Denny
a5c8552937 [WIP] new AFSK1200 decoder. 2018-06-09 04:38:47 -04:00
Denny
e4209c8e4f [WIP] Updates the passport decoder to use the new LTRDecoder.
Deprecates the Listener<Boolean> interface method in the MessageFramer
to optimize for primitive booleans and reduce impact on memory.  Will
remove this interface once the AFSK1200 decoders are updated.
2018-06-02 09:31:49 -04:00
Denny
a898be265f [WIP] Updates the LTR-Standard and LTR-Net decoders to use a new LTR
decoder with a zero-crossing symbol timing error detector.  The new
decoder is optimized for 8 kHz FM demodulated audio produced by the
AudioModule.
2018-06-02 08:47:48 -04:00
Denny
c13315f731 [WIP] The Two-Channel synthesizer is now fully-functional and the
channelizer sub-system is functionally complete.

Updated the channelizer and synthesizer filter design methods to use a
Kaiser windowed Nyquist filter.  Updated the synthesizer filter design
to use a new cutoff frequency of 105% of the channel bandwidth to
resolve a slight dip in the synthesized channel gain at the channel
union region.

Updated the 2 channel output processor to use a low-pass filter that
is designed for the runtime channel sample rate versus hard-coded 12.5
khz.

Testing and redesign continues ...
2018-05-20 07:21:14 -04:00
Denny
341e740e77 [WIP] updated the 2 channel synthesizer to use a more SIMD friendly
filter structure.  Updated the channel results array buffer to produce
reusable buffers.

This has dropped the overall memory usage considerably when profiling.

Resolved issue in the processing chain where polyphase channel sources
were not being stopped and were stacking up in memory.
2018-05-10 08:08:20 -04:00
Denny
cbc228d798 [WIP] The 2 channel synthesizer appears to be working after restructuring.
Check-point commit.  I'm going to optimize the code so that it can
leverage SIMD instructions.
2018-05-06 07:37:24 -04:00
Denny
488b2e02ce [WIP] Work continues on resolving issues with the 2-channel synthesizer
that is currently up/down converting the signal of interest, but the
synthesizer is not correctly combining the original two channels.

Some experimentation with the tap count for the channelizer indicates
that we can cut the tap count in half and still have decent decoding
on the P25 decoder when paired to an aligned channelized output.  The
2-channel synthesized output decodes partially, but needs more work.

Resolved issue with channel gain in the channelizer that was making the
sample values so small that they were registering as zero when converted
from float to 16-bit int value in the complex wave recorder.
2018-04-29 06:19:39 -04:00
Denny
e395d737f8 [WIP]-39 updates to resolve issue with stopping channel streams. 2018-04-22 04:44:35 -04:00
Denny
7a9f705517 Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java
2018-04-18 06:00:57 -04:00
Denny
dfaf506e23 Updates changelog 2018-04-18 05:52:15 -04:00
Denny
81c9a352a8 Updates changelog 2018-04-18 05:51:55 -04:00
Denny
e6937764c3 Merge remote-tracking branch 'origin/master' 2018-04-18 05:49:16 -04:00
Denny
5bfc5bf456 Increments build to 0.3.4 beta 2 2018-04-18 05:49:04 -04:00
Denny Sheirer
ce83273393 Merge pull request #345 from DSheirer/344-p25-c4fm-agc
344 Add AGC to P25 C4FM decoder
2018-04-18 09:48:19 +00:00
Denny
95aa9f8803 Adds automatic gain control to P25 C4FM decoder to condition the
samples prior to interpolation.

Resolves issue with using incorrect quadrature index when pulling a
sample from the interpolating buffer.

Resolves issue where the instrumented version of the interpolating
buffer was being constructed in the non-interpolated decoder component.
2018-04-18 05:47:17 -04:00
Denny
e971ad4582 39 [WIP] - restructured the polyphase filter process. Previous version
was not computationally feasible with my 3rd Gen i7 processor running
and airspy at 10 MHz.  Restructured the polyphase channelizer to use
vector iteration structures that the JDK 9 JIT compiler can translate
into SIMD instructions.  Separated the IFFT processing from the filter
process so that they can be executed on separate threads and this allows
the processing to occur real time.

P25 C4FM decoding at 25 kHz channel sample rate using an airspy
10MHz sample stream seems to be working nicely with ~25% CPU usage and
~300 to 500 MB memory usage.  Incremental (parallel) channel decoding
should have a minimal increase in CPU loading since all of the 12.5 kHz
channels are available in the polyphase channelizer and the only
additional workload is the decoding of the 25 kHz sample stream.

There is still an issue with stopping channels and the channelizer keeps
 processing, and occasionally when starting traffic channels something
 deadlocks and causes out of memory.
2018-04-15 09:05:06 -04:00
Denny
ff9395e4b9 39 [WIP] working copy with new SIMD structures in place. 2018-04-14 07:23:33 -04:00
Denny
d023da9ead 39 [WIP] experiments to reduce processing time for high sample rate tuners (e.g airspy) 2018-03-26 09:47:32 -04:00
Denny
60ffb18cd9 39 [WIP] cleans up the reusable buffers and creates both real and
complex variants.
2018-03-25 09:13:03 -04:00
Denny
c36f6901af 39 - Adds P25/LSM support to the DemodulatorViewerFX application and
adds Feed forward gain support to the C4FM DQPSK demodulator which seems
to improve output from the interpolating sample buffer at each symbol
period.  Updates the symbol timing gain for C4FM to decrease the gain a
bit since the feed forward gain is providing a better interpolated symbol.
2018-03-24 11:03:18 -04:00
Denny
bfaacb309d 39 - WIP - incorporates the latest P25 C4FM decoder from master and
updates the LSM decoder to follow the same design pattern.  Adds LSM
decoder support to the demodulator viewer application.  The current
symbol timing gain for LSM is set too high -- is using the C4FM gain
and causes too much fluctuation in the timing error.
2018-03-24 06:59:41 -04:00
Denny
c3b405a752 Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/main/java/io/github/dsheirer/buffer/FloatCircularBuffer.java
#	src/main/java/io/github/dsheirer/dsp/filter/FilterFactory.java
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterView.java
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
#	src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java
#	src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java
#	src/main/java/io/github/dsheirer/dsp/mixer/Oscillator.java
#	src/main/java/io/github/dsheirer/dsp/psk/LSMDemodulator.java
#	src/main/java/io/github/dsheirer/module/decode/Decoder.java
#	src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25_LSMDecoder.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerModel.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerSourceEditor.java
#	src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java
2018-03-18 05:19:33 -04:00
Denny
3619b480f8 Updates build to 0.3.4 beta 1.
Note: build 0.3.3 was never promoted beyond beta 3, although there were
no reported issues that would have prevented a 0.3.3 release.
2018-03-17 10:43:24 -04:00
Denny Sheirer
830b2a2d34 Merge pull request #339 from DSheirer/336-audio-recording-temp-files
336 - Audio recording temporary file name
2018-03-17 14:41:14 +00:00
Denny
78bb5ffe43 Resolves #336. Updates audio recorder to use a *.tmp file extension
while the file is open/in-use and change the file extension to *.wav
when the recording is closed.
2018-03-17 10:39:35 -04:00
Denny Sheirer
5dd1664844 Merge pull request #338 from DSheirer/330-p25-c4fm-decoder-update
330 p25 c4fm decoder update
2018-03-17 13:51:19 +00:00
Denny
8868c1f954 330 - updates P25 C4FM decoder to use the new DQPSK demodulator and
removes the previous FM demodulator based decoder.
2018-03-17 09:45:23 -04:00
Denny
646bd78037 330-WIP - adds the message decoder to see the P25 messages being decoded
as we step through the recording.
2018-03-04 20:41:43 -05:00
Denny
5af4cb8706 330-WIP - adds the message decoder to see the P25 messages being decoded
as we step through the recording.
2018-03-04 12:07:29 -05:00
Denny
45a6c5a0b6 330 WIP - implements the new data-directed symbol timing and phase
error calculator.  After increasing the gain for symbol timing, this
new symbol evaluator class seems to track the signal very accurately
despite lots of noise and ISI.
2018-03-04 11:42:23 -05:00
Denny
b563f2d11b 330 WIP - created new symbol evaluator class that combines phase and
timing error calculation with symbol decision.  In the process of
changing over to this new class and remove the previous implementations
for the 3 values.  This commit includes the partial implementation
so I can access from another dev machine.
2018-02-27 05:57:48 -05:00
Denny
148ddd0bd5 330 WIP - P25 C4FM decoder fully functional using DQPSK decoder and
new symbol timing error detector.  Each component now has a subclass
that supports instrumentation for use with the DemodulatorViewerFX
application.
2018-02-25 08:56:34 -05:00
Denny
a0630102e6 330 WIP - P25 C4FM decoder fully functional using DQPSK decoder and
new symbol timing error detector.
2018-02-25 05:04:20 -05:00
Denny
3d1ac30646 330 WIP - changing to 45 degree rotation before demodulation. 2018-02-20 05:27:33 -05:00
Denny
dda37a1198 330 WIP - updates the demodulator viewer with an eye diagram and symbol
chart.  Testing various configurations to see which yields the best
PLL and symbol timing locks.
2018-02-18 16:20:45 -05:00
Denny
eaf7c7d11e 330 WIP on redesigning the P25 C4FM decoder. Creates a new decoder
based on the P25 LSM decoder using a costas loop and a gardner detector.
Updates the Demodulator Viewer FX application to add in a symbol chart
and a phase error chart.  The decoder won't lock on yet ... still a wip.
2018-02-17 13:41:36 -05:00
Denny
80c5ad1bc8 WIP - updates to the demodulator viewer app and the recently used files
menu.
2018-02-13 12:31:50 +00:00
Denny
956bf2d76a Adds phase viewer and recent files menu item to viewer desktop. 2018-02-12 12:34:42 +00:00
Denny
1406d5576a 330 - Adds new JavaFX implementation of the demodulator viewer applicaiton
with initial support for playback control and I/Q sample axis viewing.
2018-02-11 10:16:50 -05:00
Denny
03e39f3343 Merge branch 'master' into 330-p25-c4fm-decoder-update 2018-02-11 06:14:23 -05:00
Denny
28f351287c 328 - cleanup issue with NPE 2018-02-11 06:13:56 -05:00
Denny
54227703a2 Cleanup from last PR. 2018-02-11 06:12:57 -05:00
Denny
bb078de0a9 Cleanup from last PR. 2018-02-10 10:23:28 -05:00
Denny
ec30cd6305 Updates changelog 2018-02-10 08:28:40 -05:00
Denny Sheirer
5a88ac0200 Merge pull request #329 from DSheirer/328-auto-start-ordering
328 Channel Auto-Start capability
2018-02-10 08:15:10 -05:00
Denny
05eea44f7e Cleanup 2018-02-10 08:14:00 -05:00
Denny
030fc1617c 328 Channel Auto-Start capability. Adds auto-start and auto-start
ordering to each channel configuration to provide the user with greater
control over initial application startup configuration.

Adds new dialog window that displays on startup that allows the user to
invoke/cancel auto-start, or simply allow the timer to expire whereby
the channels will be auto-started.

Updates channel table model to include an auto-start column and relabels
the 'Enabled' column to read 'Playing'.

Updates channel editor to change the 'Enable/Disable' button to read
'Start/Stop'.

Changes the 'enabled' property of the channel configuration to indicate
the current 'processing' status - isProcessing().

Channel's XML configuration re-purposes the 'enabled' property to indicate
auto-start and adds a new (optional) auto-start 'order' attribute.
2018-02-10 08:09:43 -05:00
Denny Sheirer
594a77a9d0 Merge pull request #327 from DSheirer/321-channel-preferred-tuner
321 channel preferred tuner
2018-02-09 07:13:13 -05:00
Denny
c2fcc9e85d 321 - adds a preferred tuner option to the channel's source configuration
so that on startup, the application attempts to source the channel from
the preferred tuner.

If the tuner is currently not available, or if the tuner cannot source
the channel, then the next available tuner is selected.
2018-02-09 07:11:38 -05:00
Denny
28da8b2fa4 [wip] reusable buffer support. 2018-02-09 05:56:20 -05:00
Denny
1c06c4382f Adds preferred tuner to tuner source configuration. 2018-02-09 05:55:29 -05:00
Denny
28cb9d9407 [WIP] Updating dsp modules to accept variable sample rate I/Q streams
and creating a new audio resampler.
2018-02-09 05:29:07 -05:00
Denny
96d9d6f750 [WIP] Adds locking mechanism to tuner controllers so that the
polyphase channel manager can block users from changing frequency and/or
sample rate when polyphase channels are allocated.
2018-02-04 06:30:25 -05:00
Denny
85691edacb [WIP] Testing completed for channel manager allocating tuner channels
when the tuner controller indicates that there is a center DC spike
blocked region or when the tuner has clipped outer spectral regions
resulting in less than 100% usable bandwidth.
2018-02-04 04:59:27 -05:00
Denny
f2f2c92afe [WIP] Implements reusable sample buffers across all components. This
produces a significant reduction in memory usage, especially for tuners
like the airspy and hackrf that produce 10/20 MSPS sample rates.  This
is observed to be around 66% reduction in peak memory usage and provides
a more stable memory utilization across time reducing stress on the
garbage collector.

Use of these reusable memory buffers will be pushed further down into
the processing chain modules to ensure we keep new object creation
to the lowest levels possible.
2018-02-03 10:05:16 -05:00
Denny
fcd3c2fd46 [WIP] channelizer and 1/2 channel output processors along with the 2
channel synthesizer ... all appear to be functional.
2018-01-28 10:52:53 -05:00
Denny
e78d2339ff WIP - aligns the SynthesizerViewer configuration with that of the
ChannelizerViewer so that we can compare the two-channel synthesis
operations.  The SynthesizerViewer is successfully down-sampling and
synthesizing two 25.0 kHz channels into a combined 25.0 kHz channel with
no noticeable drop/nulling in the joined region.  However, the channelizer
viewer's synthesized channels definitely have a null in the joined
region.  I suspect that the channelizer is not quite where it needs to
be and am going to start experimenting there.
2018-01-27 16:27:58 -05:00
Denny
673c8a2423 WIP - two-channel output processor is correctly synthesizing a channel
and translating it by -FS/4 to correctly center the synthesized channel.
The low-pass filter is currently disabled to better troubleshoot/view the
state of the synthesized channel.  It appears that the synthesizer is
not correctly joining the channel ... instead of down-sampling and then
synthesizing the two channels, it appears to be synthesizing and then
down-sampling.  The synthesized channel has a null in the middle which
would render it unusable.
2018-01-27 15:57:22 -05:00
Denny
5a03a0038c WIP - Adds FS/4 up and down converter classes. 2018-01-27 15:37:26 -05:00
Denny
e7f7d27a1f Updates the Oscillator and LowPhaseNoiseOscillator classes to share a
common interface and abstract class.
2018-01-27 04:41:01 -05:00
Denny
0cf964fa98 Updates test tuner to cleanup the buffer reuse settings 2018-01-20 04:26:53 -05:00
Denny
b6f282a85a Polyphase Channelizer Viewer is fully functional again, now using the
TestTuner and TestTunerController implementations.  This implementation
only has support for channels that are completely centered within a
channelizer output.  Two output slice stitching to form a composite
channel will be implemented next.

Initial profiling indicates that the FFT function within the polyphase
channelizer is now the dominant processing workload - 28% cpu loading
when channelizing a 10 MHz sample rate input into 800 channels running
at 25.0 kHz each.  This is ideal for offloading to an OpenCL kernel and
running on a GPU.
2018-01-19 12:44:31 -05:00
Denny
32ab0598e8 Updates sample generator and test tuner controller to support multiple
complex buffer listeners.  Removes complex buffer broadcast support from
the source manager and renames it to channel source manager to convey
that it's only responsible for providing channels from the tuner.
2018-01-15 05:34:36 -05:00
Denny
5ae3cb38e1 Merge master and re-apply the source event structures to the DFT processor. 2018-01-15 05:03:03 -05:00
Denny
78205bb1bf Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java
2018-01-15 04:56:16 -05:00
Denny Sheirer
3d9b38bef5 Merge pull request #319 from DSheirer/318-dft-processor-non-blocking-queue
318 DFT Processor Non-Blocking Queue redesign
2018-01-15 04:54:40 -05:00
Denny
d5b377b1af Resolves #318. Redesigns DFT processor to use a non-blocking queue approach to
access incoming buffer streams coupled with a overflowable queue that
limits the quantity of complex buffers that are cached for the DFT
processor.
2018-01-14 12:05:39 -05:00
Denny
a7a0c26b38 #39 WIP - changes for testing of the channelizer viewer. 2018-01-14 08:40:34 -05:00
Denny
d4761be00a #39 WIP - rolls back embedding source events in buffers. The channel
calculator must be updated immediately any time the tuner's center
frequency changes so that a channel can be allocated immediately.  So,
I changed source event handling to two parts where the channel calculator
is immediately updated and the channelizer configuration is deferred so
that it can happen on the buffer processor execution thread and we can
avoid any sync() locking on the channelizer or polyphase channel
sources.
2018-01-13 11:43:26 -05:00
Denny
05fa5c25fd #39 WIP - adds support for timestamped complex buffers so that decoded
messages and events can be accurately timestamped, and more importantly,
allocated traffic channels can request to be pre-loaded with buffered
samples to ensure that traffic channels don't miss any samples that
are currently missed due processing latency inherent in current buffer
sizing.  This should reduce the clipping of starting messages or voice
on the traffic channels.

Restructures processing path for tuner frequency and sample rate change
events.  The tuner now embeds these events in the sequence of buffers
that are generated immediately after the event occurs since those are
the buffers that will be impacted by the change.  Previously, the change
event would be broadcast throughout the system and would impact any
buffered/cached buffers.  This also reduces the number of source event
change listeners that have to be managed.  Note: this change is not yet
implemented in all tuners ... only in the TestTuner implementation.

Updates the polyphase channelizer to now buffer channel results and then
dispatch the buffer to the channel output processors to improve efficiency
of using float arrays versus single value complex float processing.
2018-01-13 09:10:57 -05:00
Denny Sheirer
69e9bed2af Updated readme 2018-01-12 03:50:57 -05:00
Denny
d2e7f008c8 WIP - implements tuner source manager to calculate and update the tuner's
center frequency each time we allocate a new DDC/channel.  Adds
 support for broadcasting channel count change source events so that the
 tuner can accurately convey sourced channel counts via tuner events.

 Completes changeover of polyphase channel manager to support arbitrary
 bandwidth channels.  The new approach provides greater compatibility
 across any tuner sample rates.  Likewise, all decoders will have to be
 updated to adapt to any channel sample rate, although channel bandwidths
 will be at least 12.5 kHz and likely no more than 25.0 kHz, with a 2x
 oversampling that produces channel sample rates in range 25.0 - 50.0
 kHz.
2018-01-07 07:46:41 -05:00
Denny
ddad4b6fb0 Updates readme 2018-01-01 13:16:20 -05:00
Denny
b65dd7e414 Updates readme 2018-01-01 08:20:30 -05:00
Denny
b076587f30 Updates readme 2018-01-01 08:17:42 -05:00
Denny
336669f1d5 Updates build version to 0.3.3 beta 3 2018-01-01 07:26:42 -05:00
Denny Sheirer
46cf7f4193 Merge pull request #309 from DSheirer/308-icon-manager-npe
308 IconManager throws NPE when loading external icons
2018-01-01 07:25:29 -05:00
Denny
e9aeb09011 Resolves issues with NPE handling and loading external icons. 2018-01-01 07:24:37 -05:00
Denny
236df8f3f4 Merges from master branch. 2017-12-27 10:10:51 -05:00
Denny
667c50174d Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	.idea/dictionaries/denny.xml
#	.idea/libraries/imports.xml
#	sdrtrunk.iml
#	src/audio/AudioModule.java
#	src/audio/broadcast/StreamManager.java
#	src/buffer/FloatCircularBuffer.java
#	src/channel/state/AlwaysUnsquelchedDecoderState.java
#	src/channel/state/ChannelState.java
#	src/channel/state/DecoderState.java
#	src/channel/traffic/TrafficChannelManager.java
#	src/controller/channel/Channel.java
#	src/dsp/filter/FilterFactory.java
#	src/dsp/filter/Window.java
#	src/dsp/filter/design/FilterView.java
#	src/dsp/filter/design/FilterViewer.java
#	src/dsp/filter/fir/FIRFilterSpecification.java
#	src/dsp/filter/fir/remez/RemezFIRFilterDesigner.java
#	src/dsp/gain/AutomaticGainControl.java
#	src/dsp/gain/ComplexFeedForwardGainControl.java
#	src/dsp/mixer/Oscillator.java
#	src/dsp/psk/LSMDemodulator.java
#	src/gui/control/JFrequencyControl.java
#	src/instrument/tap/stream/BinaryTapViewPanel.java
#	src/module/Module.java
#	src/module/ProcessingChain.java
#	src/module/decode/Decoder.java
#	src/module/decode/am/AMDecoder.java
#	src/module/decode/fleetsync2/Fleetsync2Decoder.java
#	src/module/decode/fleetsync2/Fleetsync2DecoderState.java
#	src/module/decode/lj1200/LJ1200Decoder.java
#	src/module/decode/lj1200/LJ1200DecoderState.java
#	src/module/decode/ltrnet/LTRNetDecoder.java
#	src/module/decode/ltrnet/LTRNetDecoderState.java
#	src/module/decode/ltrstandard/LTRStandardDecoder.java
#	src/module/decode/ltrstandard/LTRStandardDecoderState.java
#	src/module/decode/mdc1200/MDCDecoder.java
#	src/module/decode/mdc1200/MDCDecoderState.java
#	src/module/decode/mpt1327/MPT1327Decoder.java
#	src/module/decode/mpt1327/MPT1327DecoderState.java
#	src/module/decode/nbfm/NBFMDecoder.java
#	src/module/decode/p25/C4FMSymbolFilter.java
#	src/module/decode/p25/P25Decoder.java
#	src/module/decode/p25/P25DecoderState.java
#	src/module/decode/p25/P25_C4FMDecoder.java
#	src/module/decode/p25/P25_LSMDecoder.java
#	src/module/decode/p25/audio/P25AudioModule.java
#	src/module/decode/passport/PassportDecoder.java
#	src/module/decode/passport/PassportDecoderState.java
#	src/module/decode/tait/Tait1200Decoder.java
#	src/module/decode/tait/Tait1200DecoderState.java
#	src/module/demodulate/am/AMDemodulatorModule.java
#	src/module/demodulate/audio/DemodulatedAudioFilterModule.java
#	src/module/demodulate/fm/FMDemodulatorModule.java
#	src/module/log/EventLogger.java
#	src/record/AudioRecorder.java
#	src/record/RecorderManager.java
#	src/record/wave/ComplexBufferWaveRecorder.java
#	src/record/wave/RealBufferWaveRecorder.java
#	src/sample/Broadcaster.java
#	src/sample/OverflowableTransferQueue.java
#	src/sample/SampleType.java
#	src/source/ComplexSource.java
#	src/source/ISourceEventProvider.java
#	src/source/InvalidFrequencyException.java
#	src/source/RealSource.java
#	src/source/Source.java
#	src/source/config/SourceConfigRecording.java
#	src/source/config/SourceConfigTuner.java
#	src/source/heartbeat/Heartbeat.java
#	src/source/heartbeat/IHeartbeatListener.java
#	src/source/heartbeat/IHeartbeatProvider.java
#	src/source/mixer/RealMixerSource.java
#	src/source/recording/Recording.java
#	src/source/recording/RecordingSourceManager.java
#	src/source/tuner/ITunerChannelProvider.java
#	src/source/tuner/Tuner.java
#	src/source/tuner/TunerClass.java
#	src/source/tuner/TunerController.java
#	src/source/tuner/TunerEditor.java
#	src/source/tuner/TunerManager.java
#	src/source/tuner/TunerModel.java
#	src/source/tuner/TunerSourceEditor.java
#	src/source/tuner/TunerType.java
#	src/source/tuner/airspy/AirspyTuner.java
#	src/source/tuner/airspy/AirspyTunerController.java
#	src/source/tuner/airspy/AirspyTunerEditor.java
#	src/source/tuner/configuration/TunerConfigurationModel.java
#	src/source/tuner/fcd/FCDTuner.java
#	src/source/tuner/fcd/FCDTunerController.java
#	src/source/tuner/fcd/proV1/FCD1TunerController.java
#	src/source/tuner/fcd/proV1/FCD1TunerEditor.java
#	src/source/tuner/fcd/proplusV2/FCD2TunerController.java
#	src/source/tuner/fcd/proplusV2/FCD2TunerEditor.java
#	src/source/tuner/hackrf/HackRFTuner.java
#	src/source/tuner/hackrf/HackRFTunerController.java
#	src/source/tuner/hackrf/HackRFTunerEditor.java
#	src/source/tuner/rtl/RTL2832Tuner.java
#	src/source/tuner/rtl/RTL2832TunerController.java
#	src/source/tuner/rtl/e4k/E4KTunerController.java
#	src/source/tuner/rtl/e4k/E4KTunerEditor.java
#	src/source/tuner/rtl/r820t/R820TTunerController.java
#	src/source/tuner/rtl/r820t/R820TTunerEditor.java
#	src/source/tuner/usb/USBTransferProcessor.java
#	src/source/wave/ComplexWaveSource.java
#	src/source/wave/RealWaveSource.java
#	src/spectrum/ChannelSpectrumPanel.java
#	src/spectrum/DFTProcessor.java
#	src/spectrum/OverlayPanel.java
#	src/spectrum/SpectralDisplayPanel.java
2017-12-26 08:35:33 -05:00
Denny
c7f00ea124 Updates version to 0.3.3 beta 2 2017-12-26 07:19:06 -05:00
Denny Sheirer
1759f4a804 Merge pull request #306 from DSheirer/305-gradle-icons-missing
305 Icons missing from gradle build
2017-12-26 07:17:12 -05:00
Denny
3d9044802e Resolves issue with including icons in gradle build product. Updates
all icon handling code to use absolute path for bundled icons.
2017-12-26 07:13:15 -05:00
Denny
42aec490bd Updates build version and changelog. 2017-12-25 07:42:56 -05:00
Denny Sheirer
c3f5c1c70e Merge pull request #303 from DSheirer/278-wave-metadata
278 Add Metadata to WAV audio recordings
2017-12-25 07:17:08 -05:00
Denny
188a521770 Adds wave file ID3 metadata chunk to audio recordings.
Updates wave writer to add the metadata LIST and ID3 chunks to the end
of the recording so that the file contains the final/complete set of
metadata that was accumulated over the call lifecycle.
2017-12-25 07:08:55 -05:00
Denny
6e352143d2 Adds wave file LIST metadata chunk to audio recordings.
Note: the metadata chunk may be added multiple times over the life span
of an audio call, as additional metadata details are added.
2017-12-24 06:51:09 -05:00
Denny Sheirer
7391265949 Merge pull request #302 from DSheirer/tsypuk-SDR-build
Gradle Build System
2017-12-21 20:55:44 -05:00
Denny
26b97f09b7 Updates SettingsManager to use jackson xml serialization. Final
testing on all changes to xml serialization.
2017-12-21 19:59:11 -05:00
Denny
1d2d9e8630 Updates IconManager to use faster jackson XML serialization. 2017-12-21 13:42:03 -05:00
Denny
ee6aeafa84 Updates PlaylistManager to use faster jackson XML serialization.
Removes native xml.bind serialization for improved compatibility with
 Java 9.

 Global optimize imports on the entire project.
2017-12-21 07:18:27 -05:00
Denny
47cc194415 Resolves issue with runtime exception when identifying application
version string from jar manifest
2017-12-17 07:34:47 -05:00
Denny
9316599dec Updates pull request from Roman Tsypuk to convert the build system from
ant to gradle.  Removes linux and windows application launch scripts and
produces an executable jar with all resources included.
2017-12-17 07:28:06 -05:00
Roman Tsypuk
a1535c4157 updated README, gitignore, moved styles 2017-12-16 11:12:59 +02:00
Roman Tsypuk
b478068475 - cosmetics naming changes 2017-12-16 10:44:54 +02:00
Roman Tsypuk
7286c978da updated gitignore 2017-12-16 10:36:04 +02:00
Roman Tsypuk
628d514462 - updated to current version 2017-12-16 01:05:07 +02:00
Roman Tsypuk
3478702845 - removed scripts 2017-12-16 01:04:14 +02:00
Roman Tsypuk
695d622603 - added fatJar task 2017-12-16 00:57:44 +02:00
Roman Tsypuk
e8e47bfb40 - moved to package in.ua.smartjava 2017-12-16 00:56:22 +02:00
Roman Tsypuk
c1a4425969 - cleanup 2017-12-16 00:27:12 +02:00
Roman Tsypuk
4fa1a1aa81 - moved dependencies to gradle 2017-12-16 00:23:12 +02:00
Roman Tsypuk
4e1f9bcf97 - moved dependencies lib4java to gradle 2017-12-16 00:09:43 +02:00
Roman Tsypuk
50bb96b14a - moved dependencies to gradle 2017-12-16 00:01:23 +02:00
Roman Tsypuk
51ea70f279 moved resource files 2017-12-15 23:57:27 +02:00
Roman Tsypuk
e15f271a54 - moved dependencies to gradle 2017-12-15 23:56:28 +02:00
Roman Tsypuk
605475c98b - moved dependencies to gradle 2017-12-15 23:38:22 +02:00
Roman Tsypuk
86248c511a updated gitignore 2017-12-15 23:23:42 +02:00
Roman Tsypuk
b1e07f762c fix src folder structure 2017-12-15 23:22:32 +02:00
Roman Tsypuk
f2d1ac7e48 - commons moved to gradle 2017-12-15 22:56:38 +02:00
Roman Tsypuk
d114282e4b added dependencies from import folder 2017-12-15 22:53:33 +02:00
Roman Tsypuk
0fd20655fa - added gradle wrapper 2017-12-15 22:52:42 +02:00
Roman Tsypuk
181527f54c - added gradle build 2017-12-15 22:45:40 +02:00
Roman Tsypuk
910587bad7 - updated gitignore 2017-12-15 22:44:29 +02:00
Denny Sheirer
1dc9a7fb0e Merge pull request #300 from DSheirer/299-traffic-channel-event-logging
299 Traffic Channel Event Logging
2017-12-11 21:08:09 -05:00
Denny
eef29d28da #299 - adds support for traffic channel event logging of binary or
decoded messages and event logging, as inherited from the parent
control channel's configuration.
2017-12-11 21:07:30 -05:00
Denny
1c71a37755 #39 WIP - 2017-12-11 20:30:19 -05:00
Denny
318e6f3586 #39 WIP - changes tuner controllers to expose the frequency controller
and the channel manager in preparation for polyphase.
2017-12-11 20:27:01 -05:00
Denny
f38184fd83 #39 WIP - finishes polyphase channel source processing of frequency
offset calculation and updating for channel frequency correction.
2017-12-10 06:26:44 -05:00
Denny
d2085052f6 #39 WIP - updates tunerchannelsource as the parent class for the CIC
and polyphase sub class implementations.  Converts all source implementations
and tuners to treat sample rate as a double.
2017-12-09 15:23:40 -05:00
Denny
441b595325 #39 WIP - initial efforts to restructure the way tuners and tuner
controllers manager sample buffer processing and channel management.
General cleanup across all modules to remove the executor from each
of the start() methods.  Removed the B100 tuner class since it's not
yet implemented.
2017-12-08 04:02:49 -05:00
Denny
57fab2b7ca #39 WIP - initial efforts to restructure the way tuners and tuner
controllers manager sample buffer processing and channel management.
General cleanup across all modules to remove the executor from each
of the start() methods.  Removed the B100 tuner class since it's not
yet implemented.
2017-12-03 11:10:50 -05:00
Denny
bf65e10286 #39 WIP polyphase channelizer
Updates the M2 channelizer and correctly implements the ChannelCalculator
2017-12-02 08:58:34 -05:00
Denny Sheirer
a3ecb339be Merge pull request #294 from DSheirer/241-lj1200-crc-error-checking
241 LJ1200 Error Correction
2017-12-02 03:16:29 -05:00
Denny
910a08f7bb #241 Resolves issue with error correction routine introducing invalid messages 2017-12-02 03:15:31 -05:00
Denny
5a76f31dea Updated change log 2017-11-23 07:37:53 -05:00
Denny Sheirer
1b42e64f50 Merge pull request #290 from DSheirer/289-shoutcast-2-credentials-encryption-error
289 Shoutcast 2 Login Error
2017-11-23 07:30:45 -05:00
Denny
1ddc0a33a5 #289 resolves issue with encrypting username and password with XTEA
algorithm using credential values longer than 8 characters/bytes.
2017-11-23 07:28:15 -05:00
Denny
a12aaf7cf3 #39 WIP polyphase channelizers. 2017-11-18 07:33:28 -05:00
Denny
b3e4bd6a9c #39 WIP polyphase channelizers. 2017-11-18 05:50:00 -05:00
Denny
5281679b7f #39 WIP polyphase channelizers. Creates test tuner and controller to
use in testing tuner and polyphase channel manager operations.
2017-11-12 10:33:13 -05:00
Denny
a581da56a8 #39 WIP polyphase channelizers. 2017-11-05 11:38:01 -05:00
Denny Sheirer
88580af436 Merge pull request #284 from DSheirer/283-broadcastify-text-html-response
283 Broadcastify mount point in use error
2017-11-04 13:31:40 +00:00
Denny
64688a3c20 Updates CHANGELOG 2017-11-04 09:07:46 -04:00
Denny
8be3399a6b Issue #283
Updates Icecast TCP broadcaster to correctly handle content type:text/html
message that normally follows mount point in use error received from
broadcastify.

Changes mount point in use broadcast state to be a temporary error so that
the stream will attempt to reconnect after receiving this error.

Updates logging to include memory allocation/usage metrics with each
logging entry in order to support debugging issues related to high
memory usage situations.  Updates initial application logging to better
identify the host system operating environment.
2017-11-04 09:02:03 -04:00
Denny
0181926fe3 WIP - polyphase channelizer 2017-10-30 19:12:14 -04:00
Denny
2c3be02939 WIP - polyphase channelizer 2017-10-23 08:43:53 -04:00
Denny
a00ec42230 Cleanup from master merge 2017-10-22 06:37:24 -04:00
Denny
14a3532030 Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/source/tuner/TunerController.java
2017-10-22 06:28:57 -04:00
Denny Sheirer
28340809ca Merge pull request #279 from DSheirer/276-traffic-channel-manager-deadlocked-threads
276 TrafficController Infinite Loop
2017-10-21 09:43:42 -04:00
Denny
f3d3a8187a Resolves #276 Traffic Channel threads locking in overflow state. Issue
occured when the ChannelProcessionManager was allocating a new channel
causing the tuner to invoke the updateLOFrequency() method that was
trying to find a center tune frequency that would accommodate all of the
channels, specifically in the instance where the distance between the
highest channel and the middle channel was exactly one-half of the
tuner's bandwidth.  This situation would cause the calculated adjustment
to be zero and would cause an infinite loop, locking all channels from
accessing the any channel startup/teardown events and causing running
channels to block with buffer overflows. Added 1 to the adjustment to
ensure that the initial adjustment placed the center overlapping channel
fully to the left of the center DC spike so that on the next iteration
that channel would no longer be overlapping.
2017-10-21 09:31:34 -04:00
Denny Sheirer
8484e837b8 Merge pull request #277 from DSheirer/273-gui-title-version
273 Application Title Version String
2017-10-16 19:38:15 -04:00
Denny
01b188ea25 Resolves #273 issue with dangling dash in application title version string. 2017-10-16 19:37:11 -04:00
Denny
3be65d5e9a Resolves issue from merging master branch into polyphase channelizer branch. 2017-10-15 07:26:17 -04:00
Denny
c21f3fca23 Resolves issue from merging master onto branch. 2017-10-15 07:19:36 -04:00
Denny
99d81d247a Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/channel/state/ChannelState.java
#	src/module/ProcessingChain.java
#	src/source/Source.java
#	src/source/mixer/RealMixerSource.java
#	src/source/tuner/TunerChannelSource.java
#	src/source/wave/RealWaveSource.java
2017-10-15 07:17:57 -04:00
Denny
27461df7f0 WIP on 2 channel output processor 2017-09-18 04:15:04 -04:00
Denny
9983d2119d WIP 2017-09-10 04:42:35 -04:00
Denny
9e275b7d62 WIP 2017-09-02 06:55:58 -04:00
Denny
f461ed9cdb wip-channelizer 2017-05-13 10:16:18 -04:00
Denny
7c6b7494b8 wip-channelizer 2017-04-21 12:17:55 -04:00
Denny
ab31b40124 Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/spectrum/SpectrumPanel.java
2017-04-14 14:42:56 -04:00
Denny
ac686f5f64 WIP - correctly implements the 2x oversampled polyphase channelizer. 2017-04-14 06:41:43 -04:00
Denny
f7cd798f07 WIP 2017-04-08 08:35:48 -04:00
Denny
41d307cdad WIP - checkpointing update for 2x oversampling where we're only computing half of the coefficients. 2017-04-03 19:04:00 -04:00
Denny
afae1654d5 WIP 2017-04-01 15:10:02 -04:00
Denny
ffc92a8f0e WIP - adds remez channelizer builder, working toward combined support (remez & sync) via the filter factory. 2017-03-30 19:16:37 -04:00
Denny
6d9e129087 WIP - adds windowed-sinc (nyquist) filter designer and polyphase channelizer filter designer to FilterFactory. Resolves a few issues with Window designers. ChannelizerViewer is now able to show 800 channels with 12.5 kHz channelization of a 10 MHz bandwidth input signal. 2017-03-26 10:23:38 -04:00
Denny
0e1da8fb3b Updates intellij files and includes missing library 2017-03-23 11:31:15 +00:00
Denny
7d5371db4c Updates build to 0.3.0 Beta 9 2017-03-20 06:12:15 -04:00
Denny
131290fcd2 WIP - experiments 2017-03-11 06:08:23 -05:00
Denny
e2fe06638b Incrementing build to version 0.3.0 beta8 2017-03-05 05:55:04 -05:00
Denny
17c16e16ee Adds a new remez designer that uses BigDecimal to handle the larger values inherent in longer length filters. However, this designer is hugely inefficient and takes forever to calculate the filter. More experimentation needed. 2017-03-02 19:17:22 -05:00
Denny
cd4eaedfcc Merge branch 'master' into 39-polyphase-channelizer 2017-02-26 13:35:33 -05:00
Denny
fd748fec79 [WIP] Using different filters 2017-02-20 20:16:38 -05:00
Denny
14b844f0bd [WIP] Channelizing 6.4 MHz sample rate into 512 channels with with 512-point FFT on each channel at frame rate of 20 fps. 2017-02-19 10:37:44 -05:00
Denny
99ef002d07 [WIP] working on polyphase channelizer and testing viewer 2017-02-19 08:22:37 -05:00
Denny
e868428c88 [WIP] working on polyphase channelizer and testing viewer 2017-02-18 11:05:21 -05:00
Denny
d2542d2560 Merge branch 'master' into 39-polyphase-channelizer
# Conflicts:
#	src/dsp/filter/design/FilterViewer.java
2017-02-18 07:34:18 -05:00
Denny
9ca87299d5 [WIP] Polyphase channelizer experiments 2017-02-06 04:19:09 -05:00
2397 changed files with 212171 additions and 119437 deletions

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="imports/commons-lang3-3.2.1.jar"/>
<classpathentry kind="lib" path="imports/jide-oss-3.5.15.jar"/>
<classpathentry kind="lib" path="imports/jsr80-1.0.1.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-arm.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86.jar"/>
<classpathentry kind="lib" path="imports/miglayout-4.0-swing.jar"/>
<classpathentry kind="lib" path="imports/usb-api-1.0.2.jar"/>
<classpathentry kind="lib" path="imports/usb4java-1.2.0.jar"/>
<classpathentry kind="lib" path="imports/usb4java-javax-1.2.0.jar"/>
<classpathentry kind="lib" path="config"/>
<classpathentry kind="lib" path="imports/JTransforms-3.0.jar" sourcepath="/home/denny/.m2/repository/com/github/wendykierp/JTransforms/3.0/JTransforms-3.0-sources.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-ppc.jar"/>
<classpathentry kind="lib" path="imports/JLargeArrays-1.2.jar"/>
<classpathentry kind="lib" path="imports/slf4j-api-1.7.7.jar"/>
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/commons-io-2.4.jar"/>
<classpathentry kind="lib" path="imports/jmbe-interface-0.3.2.jar"/>
<classpathentry kind="lib" path="imports/tablefilter-swing-5.2.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/home/denny/Downloads/tablefilter-swing-5.2.1-javadoc.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -1,4 +0,0 @@
[Dolphin]
Timestamp=2015,9,8,20,39,49
Version=3
ViewMode=1

35
.gitignore vendored
View File

@@ -1,6 +1,35 @@
*.class
### JetBrains template
.idea/
/classes*
/product*
/bin*
out/
.directory
.settings
.settings
## File-based project format:
*.iws
*.iml
# mpeltonen/sbt-idea plugin
.idea_modules/
### Java template
*.class
*.log
# Package Files #
#*.jar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Gradle template
.gradle
/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

22
.idea/compiler.xml generated
View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,9 +0,0 @@
<component name="CopyrightManager">
<settings default="sdrtrunk">
<LanguageOptions name="__TEMPLATE__">
<option name="addBlankAfter" value="false" />
<option name="separateBefore" value="true" />
<option name="separateAfter" value="true" />
</LanguageOptions>
</settings>
</component>

View File

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

View File

@@ -3,19 +3,27 @@
<words>
<w>bahroo</w>
<w>broadcastify</w>
<w>correlator</w>
<w>dinf</w>
<w>esnid</w>
<w>fleetsync</w>
<w>heterdyned</w>
<w>heterodynes</w>
<w>icecast</w>
<w>ident</w>
<w>nutall</w>
<w>overflowable</w>
<w>polyphase</w>
<w>qpsk</w>
<w>remez</w>
<w>resampler</w>
<w>samplerate</w>
<w>sdrtrunk</w>
<w>sheirer</w>
<w>shoutcast</w>
<w>streamable</w>
<w>talkgroup</w>
<w>talkgroups</w>
<w>tgid</w>
<w>ultravox</w>
<w>wacn</w>

View File

@@ -1,35 +0,0 @@
<component name="libraryTable">
<library name="imports">
<CLASSES>
<root url="jar://$PROJECT_DIR$/imports/logback-classic-1.1.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/usb-api-1.0.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/commons-io-2.4.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/commons-lang3-3.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/tablefilter-swing-5.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-linux-x86.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/JLargeArrays-1.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-linux-ppc.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-windows-x86.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-osx-x86.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/miglayout-4.0-swing.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-windows-x86_64.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/usb4java-1.2.0.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/jide-oss-3.5.15.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-linux-x86_64.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/logback-core-1.1.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/usb4java-javax-1.2.0.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/jsr80-1.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-linux-arm.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-osx-x86_64.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/JTransforms-3.0.jar!/" />
<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/commons-codec-1.9.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/commons-logging-1.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/slf4j-api-1.7.21.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/libusb4java-1.2.0-linux-aarch64.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,20 +0,0 @@
<component name="libraryTable">
<library name="org.asynchttpclient:async-http-client:2.0.18" type="repository">
<properties maven-id="org.asynchttpclient:async-http-client:2.0.18" />
<CLASSES>
<root url="jar://$PROJECT_DIR$/imports/slf4j-api-1.7.21.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/javassist-3.20.0-GA.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/axis.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/jaxrpc.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/commons-discovery-0.2.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/activation-1.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/java-mail-1.4.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/wsdl4j-1.5.1.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/radioreference-14.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/mina-core-2.0.16.jar!/" />
<root url="jar://$PROJECT_DIR$/imports/mina-http-2.0.16.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

41
.idea/misc.xml generated
View File

@@ -1,44 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ClientPropertiesManager">
<properties class="javax.swing.AbstractButton">
<property name="hideActionText" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JComponent">
<property name="html.disable" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JEditorPane">
<property name="JEditorPane.w3cLengthUnits" class="java.lang.Boolean" />
<property name="JEditorPane.honorDisplayProperties" class="java.lang.Boolean" />
<property name="charset" class="java.lang.String" />
</properties>
<properties class="javax.swing.JList">
<property name="List.isFileList" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JPasswordField">
<property name="JPasswordField.cutCopyAllowed" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JSlider">
<property name="Slider.paintThumbArrowShape" class="java.lang.Boolean" />
<property name="JSlider.isFilled" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JTable">
<property name="Table.isFileList" class="java.lang.Boolean" />
<property name="JTable.autoStartsEdit" class="java.lang.Boolean" />
<property name="terminateEditOnFocusLost" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JToolBar">
<property name="JToolBar.isRollover" class="java.lang.Boolean" />
</properties>
<properties class="javax.swing.JTree">
<property name="JTree.lineStyle" class="java.lang.String" />
</properties>
<properties class="javax.swing.text.JTextComponent">
<property name="caretAspectRatio" class="java.lang.Double" />
<property name="caretWidth" class="java.lang.Integer" />
</properties>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_13" default="false" project-jdk-name="13.0.2" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

4
.idea/modules.xml generated
View File

@@ -2,7 +2,9 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/sdrtrunk.iml" filepath="$PROJECT_DIR$/sdrtrunk.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" group="sdr-trunk" />
<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>

124
.idea/uiDesigner.xml generated
View File

@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sdrtrunk</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>

View File

@@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View File

@@ -1,5 +1,39 @@
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.0-beta1 20170129
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
auto-start. Provides user with more control over startup configuration.
- Adds preferred tuner attribute to channel configuration allowing user to select a preferred tuner for the channel
0.3.3 20171225
- Changes build system from ant to gradle. Thanks to: Roman Tsypuk https://github.com/tsypuk
- Adds LIST and ID3 metadata to wav audio recordings
0.3.2 20171105
- Resolves issue with tuner frequency adjustments that was causing channel processing
to lockup and show persistent 'overflow' state in each channel status
- Resolves issue with broadcastify 'mountpoint-in-use' error handling and updates
memory usage logging
- Resolves issue with Shoutcast 2 login error
0.3.1 20171009
- Resolves Java 9 incompatibility issues
0.3.0 20170922
- REQUIRES: Java 8 (or newer) for compatibility and eventual changeover to JavaFX
- FEATURE: audio streaming - adds capability to stream to multiple remote broadcast
servers (Broadcastify, Icecast v2.3 and v2.4+, and Shoutcast V1 and V2). Each
@@ -34,7 +68,7 @@
- Updated Baseband (I/Q) recording at 48 kHz
- Added Airspy tuner support
- New traffic channel pool manager for trunked call following
- P25 Decoder for C4FM and LSM with trunked call following and audio
- P25 Decoder for C4FM and LSM with trunked call following and audio
decoding via the JMBE library
- Updated MPT1327 decoder and trunked call following.
- Updated spectral and waterfall display with zoom (2-64x) and pan and automatic

View File

@@ -1,10 +1,67 @@
# 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)
* [User's Manual Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual_Version0.3.0)
* [Getting Started](https://github.com/DSheirer/sdrtrunk/wiki/GettingStarted_V0.3.0)
* [User's Manual Version 0.3.0 and 0.4.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual_V0.3.0)
* [Playlist Editor User Manual Version 0.5.0](https://github.com/DSheirer/sdrtrunk/wiki/Playlist-Editor)
* [Download](https://github.com/DSheirer/sdrtrunk/releases)
* [Support](https://groups.google.com/forum/#!forum/sdrtrunk)
* [Support Group](https://groups.google.com/forum/#!forum/sdrtrunk)
* [Discord Support Channel](https://discord.gg/HJQaKYE)
![sdrtrunk Application Overview - Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/images/ApplicationOverview_V0.3.0.png)
![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
# End User Instructions:
If you simply want to download and run the program, please follow these instructions.
## Download the latest sdrtrunk release for your operating system
All release versions of sdrtrunk are available from the [releases](https://github.com/DSheirer/sdrtrunk/releases) tab.
* **(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.
## Unzip the release
Use 7-zip or any zip utility to unzip the release file
## Start the application
Once unzipped, open a command prompt to where you unzipped the release. Change to the **/bin** directory and use the launch script to start the application:
* **Windows** sdr-trunk.bat
* **Linux/OSX** ./sdr-trunk
## 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. Once you have compiled the library, launch the sdrtrunk application. From the menu bar, choose **View >> Preferences**. In the **JMBE Audio Codec** section, update the path to where your compiled JMBE library is located. Any channels that are started after you set the path will be able to produce P25 audio.
## 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.
# 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 the gradle build system. This requires OpenJDK 11 or higher installed on your local compuber. Use the gradle wrapper to build the source code:
### Linux
```
./gradlew clean build
```
### Windows
```
gradlew.bat clean build
```
The **/build/distributions** folder will contain the zip file of the compiled program. Unzip it and launch the program from the scripts in the **/bin** directory.
## Development
All dependencies/versions are controlled from build.gradle.
To change the new release version tag of artifact - change property:
```
version = '0.5.0'
```

233
build.gradle Normal file
View File

@@ -0,0 +1,233 @@
/*
*
* * ******************************************************************************
* * 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/>
* * *****************************************************************************
*
*
*/
plugins {
id 'application'
id 'java'
id 'idea'
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.runtime' version '1.8.1'
}
repositories {
jcenter()
mavenCentral()
maven { url "https://jitpack.io" }
}
version = '0.5.0-alpha2'
sourceCompatibility = '13'
sourceSets {
main.java.srcDirs 'src/main'
test.java.srcDirs 'src/test'
}
dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.8.0'
//Jitpack imports
implementation 'com.github.nwaldispuehl:java-lame:v3.98.4'
implementation 'com.github.dnault:libresample4j:master'
implementation 'com.github.DSheirer.jmbe:jmbe-api:1.0.0'
//mavenCentral/jcenter imports
implementation 'ch.qos.logback:logback-core:1.2.3'
implementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8'
implementation 'com.fazecast:jSerialComm:2.5.0'
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.8.6'
implementation 'com.google.guava:guava:27.0.1-jre'
implementation 'com.jidesoft:jide-oss:3.6.18'
implementation 'com.miglayout:miglayout-swing:5.2'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'eu.hansolo:charts:1.0.5'
implementation 'io.github.dsheirer:radio-reference-api:15.1.6'
implementation 'javax.usb:usb-api:1.0.2'
implementation 'net.coderazzi:tablefilter-swing:5.4.0'
implementation 'org.apache.commons:commons-compress:1.20'
implementation 'commons-io:commons-io:2.7'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'org.apache.mina:mina-core:2.1.3'
implementation 'org.apache.mina:mina-http:2.1.3'
implementation 'org.controlsfx:controlsfx:11.0.1'
implementation 'org.rauschig:jarchivelib:1.0.0'
implementation 'org.slf4j:slf4j-api:1.7.25'
implementation 'org.usb4java:libusb4java:1.3.0'
implementation 'org.usb4java:usb4java:1.3.0'
implementation 'org.usb4java:usb4java-javax:1.3.0'
implementation 'pl.edu.icm:JLargeArrays:1.6'
//These must remain as compile options to ensure they are included in the build to produce multi-OS images
compile "org.openjfx:javafx-base:13.0.2:win"
compile "org.openjfx:javafx-base:13.0.2:linux"
compile "org.openjfx:javafx-base:13.0.2:mac"
compile "org.openjfx:javafx-controls:13.0.2:win"
compile "org.openjfx:javafx-controls:13.0.2:linux"
compile "org.openjfx:javafx-controls:13.0.2:mac"
compile "org.openjfx:javafx-graphics:13.0.2:win"
compile "org.openjfx:javafx-graphics:13.0.2:linux"
compile "org.openjfx:javafx-graphics:13.0.2:mac"
compile "org.openjfx:javafx-swing:13.0.2:win"
compile "org.openjfx:javafx-swing:13.0.2:linux"
compile "org.openjfx:javafx-swing:13.0.2:mac"
}
application {
mainClassName = "io.github.dsheirer.gui.SDRTrunk"
}
idea {
module {
downloadJavadoc = true
downloadSources = true
}
}
javafx {
modules = ['javafx.base', 'javafx.controls', 'javafx.graphics', 'javafx.swing']
}
jar {
manifest {
attributes (
'Implementation-Title' : 'sdrtrunk project',
'Implementation-Version' : archiveVersion,
'Class-Path' : 'jmbe-1.0.4.jar',
'Created-By' : "Gradle ${gradle.gradleVersion}",
'Build-Timestamp' : new java.text.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']}"
)
}
}
/**
* Java Development Kit (JDK) locations. In order to build OS-specific images, these paths must point to the 'bin'
* directory within a JDK for each of the specified architectures. These JDKs are used by the runtime and runtimeZip
* tasks to produce platform-specific builds. If none of these paths exists, then an image will be created for the
* host OS using the installed JDK.
*/
def jdk_linux_x86_64 = '/media/denny/WD250GB/java/bellsoft/linux-x64/jdk-14'
def jdk_linux_x86_32 = '/media/denny/WD250GB/java/bellsoft/linux-x86/jdk-14'
def jdk_osx_x86_64 = '/media/denny/WD250GB/java/bellsoft/osx-x64/jdk-14.jdk'
def jdk_windows_x86_64 = '/media/denny/WD250GB/java/bellsoft/windows-x64/jdk-14'
def jdk_windows_x86_32 = '/media/denny/WD250GB/java/bellsoft/windows-x86/jdk-14'
def file_jdk_linux_x86_64 = new File(jdk_linux_x86_64)
def file_jdk_linux_x86_32 = new File(jdk_linux_x86_32)
def file_jdk_osx_x86_64 = new File(jdk_osx_x86_64)
def file_jdk_windows_x86_64 = new File(jdk_windows_x86_64)
def file_jdk_windows_x86_32 = new File(jdk_windows_x86_32)
def hasTargetJdk = file_jdk_linux_x86_32.exists() ||
file_jdk_linux_x86_64.exists() ||
file_jdk_osx_x86_64.exists() ||
file_jdk_windows_x86_32.exists() ||
file_jdk_windows_x86_64.exists()
runtime {
if(file_jdk_linux_x86_64.exists())
{
targetPlatform('linux-x86_64-v' + version, jdk_linux_x86_64)
}
if(file_jdk_linux_x86_32.exists())
{
targetPlatform('linux-x86_32-v' + version, jdk_linux_x86_32)
}
if(file_jdk_osx_x86_64.exists())
{
targetPlatform('osx-x86_64-v' + version, jdk_osx_x86_64)
}
if(file_jdk_windows_x86_64.exists())
{
targetPlatform('windows-x86_64-v' + version, jdk_windows_x86_64)
}
if(file_jdk_windows_x86_32.exists())
{
targetPlatform('windows-x86_32-v' + version, jdk_windows_x86_32)
}
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
modules = ['java.desktop', 'java.naming', 'jdk.unsupported', 'jdk.unsupported.desktop', 'java.net.http',
'java.sql', 'jdk.crypto.ec']
imageZip = hasTargetJdk ? file("$buildDir/image/sdr-trunk.zip") : file("$buildDir/image/sdr-trunk-" + version + ".zip")
}
/**
* Check for existence of JDK folders for each supported platform before creating runtime images
*/
tasks.runtime.doFirst {
if(!file_jdk_linux_x86_64.exists())
{
println("Skipping OS Image - Linux x86 64-bit JDK was not found at " + jdk_linux_x86_64)
}
if(!file_jdk_linux_x86_32.exists())
{
println("Skipping OS Image - Linux x86 32-bit JDK was not found at " + jdk_linux_x86_32)
}
if(!file_jdk_osx_x86_64.exists())
{
println("Skipping OS Image - OSX x86 64-bit JDK was not found at " + jdk_osx_x86_64);
}
if(!file_jdk_windows_x86_64.exists())
{
println("Skipping OS Image - Windows x86 64-bit JDK was not found at " + jdk_windows_x86_64)
}
if(!file_jdk_windows_x86_32.exists())
{
println("Skipping OS Image - Windows x86 32-bit JDK was not found at " + jdk_windows_x86_32)
}
}
/**
* Remove unused JavaFX OS-specific libraries from each platform target directory
*/
tasks.runtime.doLast {
delete(fileTree('build/image/sdr-trunk-linux-x86_64-v' + version + '/lib').include { it.name ==~ /javafx.*-(win|mac)\.jar/ })
delete(fileTree('build/image/sdr-trunk-linux-x86_32-v' + version + '/lib').include { it.name ==~ /javafx.*-(win|mac)\.jar/ })
delete(fileTree('build/image/sdr-trunk-osx-x86_64-v' + version + '/lib').include { it.name ==~ /javafx.*-(win|linux)\.jar/ })
delete(fileTree('build/image/sdr-trunk-windows-x86_64-v' + version + '/lib').include { it.name ==~ /javafx.*-(linux|mac)\.jar/ })
delete(fileTree('build/image/sdr-trunk-windows-x86_32-v' + version + '/lib').include { it.name ==~ /javafx.*-(linux|mac)\.jar/ })
//JavaFX web and media modules are transitive dependencies of ControlsFX but are not required for this application
delete(fileTree('build/image/sdr-trunk-linux-x86_64-v' + version + '/lib').include { it.name ==~ /javafx-(web|media)-.*\.jar/ })
delete(fileTree('build/image/sdr-trunk-linux-x86_32-v' + version + '/lib').include { it.name ==~ /javafx-(web|media)-.*\.jar/ })
delete(fileTree('build/image/sdr-trunk-osx-x86_64-v' + version + '/lib').include { it.name ==~ /javafx-(web|media)-.*\.jar/ })
delete(fileTree('build/image/sdr-trunk-windows-x86_64-v' + version + '/lib').include { it.name ==~ /javafx-(web|media)-.*\.jar/ })
delete(fileTree('build/image/sdr-trunk-windows-x86_32-v' + version + '/lib').include { it.name ==~ /javafx-(web|media)-.*\.jar/ })
}

View File

@@ -1,142 +0,0 @@
<project name="SDRTrunk" default="SDRTrunk" basedir=".">
<description>
Ant build script for SDRTrunk Decoder Application
</description>
<!-- version properties -->
<property name="major" value="0"/>
<property name="minor" value="3"/>
<property name="patch" value="1"/>
<property name="release" value="final"/>
<property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/>
<!-- Build properties -->
<property name="repo" location=".."/>
<property name="source.code" location="${repo}/src"/>
<property name="source.configs" location="${repo}/config"/>
<property name="source.images" location="${repo}/images"/>
<property name="source.libs" location="${repo}/imports"/>
<property name="source.scripts" location="${repo}/scripts"/>
<property name="output" location="${repo}/product"/>
<property name="output.classes" location="${repo}/classes"/>
<property name="output.folder" location="${output}/sdrtrunk"/>
<property name="output.config" location="${output.folder}/config"/>
<property name="output.images" location="${output.folder}/images"/>
<property name="output.libs" location="${output.folder}/libs"/>
<path id="classpath">
<fileset dir="${source.libs}" includes="*.jar"/>
</path>
<target name="init">
<!-- Create the classes folder to contain the compiled java classes -->
<mkdir dir="${output.classes}"/>
<!-- Create version file -->
<echo message="${major}.${minor}.${patch}-${release}" file="${output.classes}/sdrtrunk-version"/>
</target>
<target name="compile" depends="clean,init,compile-java-8,compile-java-9"
description="Compile java classes" />
<target name="compile-java-8" depends="check-java-version" if="java.8" description="Compiles code with Java 8 arguments">
<echo message="Compiling with Java 8 Options"/>
<javac srcdir="${source.code}" destdir="${output.classes}" classpathref="classpath" includeantruntime="false"/>
</target>
<target name="compile-java-9" depends="check-java-version" if="java.9" description="Compiles code with Java 9 arguments">
<echo message="Compiling with Java 9 Options"/>
<javac srcdir="${source.code}" destdir="${output.classes}" classpathref="classpath" includeantruntime="false">
<compilerarg value="--add-modules"/>
<compilerarg value="java.xml.bind"/>
</javac>
</target>
<target name="check-java-version" description="Determines if the compiler is Java 8 or 9">
<condition property="java.8" value="true">
<contains string="${java.version}" substring="1.8"/>
</condition>
<condition property="java.9" value="true">
<equals arg1="${java.version}" arg2="9"/>
</condition>
<echo message="Java Version: ${java.version}"/>
</target>
<target name="SDRTrunk" depends="compile" description="Create SDRTrunk application">
<!-- Create the distribution directory -->
<mkdir dir="${output.folder}"/>
<!-- Create jar file -->
<jar jarfile="${output.folder}/sdrtrunk.jar" basedir="${output.classes}">
<manifest>
<attribute name="Title" value="sdrtrunk"/>
<attribute name="Main-Class" value="gui.SDRTrunk"/>
<attribute name="Version" value="${major}.${minor}.${patch}-${release}"/>
</manifest>
<fileset dir="${source.configs}">
<exclude name="*.rules"/>
</fileset>
<fileset dir="${repo}">
<include name="LICENSE"/>
</fileset>
</jar>
<!-- Copy third-party libraries -->
<mkdir dir="${output.libs}"/>
<copy todir="${output.libs}">
<fileset dir="${source.libs}" includes="*.jar"/>
</copy>
<!-- Copy config files -->
<mkdir dir="${output.config}"/>
<copy todir="${output.config}">
<fileset dir="${source.configs}">
<include name="*.rules"/>
</fileset>
</copy>
<!-- Copy image files -->
<mkdir dir="${output.images}"/>
<copy todir="${output.images}">
<fileset dir="${source.images}"/>
</copy>
<!-- Copy license file -->
<copy todir="${output.folder}">
<fileset dir="${repo}">
<include name="LICENSE"/>
</fileset>
</copy>
<!-- Copy program scripts -->
<copy todir="${output.folder}">
<fileset dir="${source.scripts}"/>
</copy>
<!-- Bundle the files into .zip -->
<zip destfile="${output}/${filename}.zip" basedir="${output}"/>
<!-- Remove linux start script before tar task -->
<delete file="${output.folder}/run_sdrtrunk_linux.sh"/>
<!-- Bundle files into .tar.gz and copy/set permissions on linux start script -->
<tar destfile="${output}/${filename}.tar.gz" compression="gzip">
<tarfileset dir="${output.folder}" prefix="sdrtrunk"/>
<tarfileset dir="${source.scripts}" prefix="sdrtrunk" filemode="777">
<include name="run_sdrtrunk_linux.sh"/>
</tarfileset>
</tar>
<delete dir="${output.folder}"/>
</target>
<target name="clean" description="Clean previous build artifacts">
<delete dir="${output.classes}"/>
<delete dir="${output}"/>
</target>
</project>

View File

@@ -1,33 +0,0 @@
<configuration>
<timestamp key="appstart" datePattern="HHmmss"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${user.home}/SDRTrunk/logs/sdrtrunk_app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily log rollover -->
<fileNamePattern>${user.home}/SDRTrunk/logs/%d{yyyyMMdd}_sdrtrunk_app.log</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-25(%d{yyyyMMdd HHmmss.SSS} [%thread]) %-5level %logger{30} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-12(%d{HH:mm:ss.SSS}) %-5level %logger{25} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
<!-- Apache Mina TCP/HTTP library -->
<logger name="org.apache.mina" level="INFO" />
</configuration>

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/>
*****************************************************************************

View File

@@ -1,17 +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/>
******************************************************************************/

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

183
gradlew vendored Executable file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# 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"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# 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
;;
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"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
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
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 or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
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, 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"
exec "$JAVACMD" "$@"

100
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,100 @@
@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
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@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="-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
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
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%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="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
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,4 +0,0 @@
[Dolphin]
PreviewsShown=true
Timestamp=2013,9,20,8,54,21
Version=3

View File

@@ -1,4 +0,0 @@
[Dolphin]
Timestamp=2013,4,7,10,12,39
Version=3
ViewMode=1

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,16 +0,0 @@
#!/bin/bash
java -version
# Test for java version 9
JAVA_9=$(java -version 2>&1 | grep -i version | sed 's/.* "\([9]\).*/\1/')
if [ -z ${JAVA_9+x} ]; then
echo Using Java 9 program options
# Java 9 uses the G1 garbage collector by default and requires that we specify the
# java.xml.bind package since it's been removed from the java se core library
java -cp "*:libs/*" --add-modules java.xml.bind gui.SDRTrunk;
else
echo Using Java 8 program options
java -XX:+UseG1GC -cp "*:libs/*" gui.SDRTrunk;
fi

View File

@@ -1,25 +0,0 @@
@echo off
java -version
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "usebackq tokens=3" %%a in (`java -version 2^>^&1 ^| find "version"`) do (
rem set b to the unquoted version string parsed from the java version command
set b=%%~a
rem set c to the first character of the unquoted version string
set c=!b:~0,1!
if !c! equ 9 (
echo Using Java 9 options
java -cp "SDRTrunk.jar;*;libs/*;config/*;images/*" --add-modules java.xml.bind gui.SDRTrunk
) else (
echo Using Java 8 options
java -XX:+UseG1GC -cp "SDRTrunk.jar;*;libs/*;config/*;images/*" gui.SDRTrunk
)
)
ENDLOCAL
@echo on

1023
sdr-trunk.ipr Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +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" />
<sourceFolder url="file://$MODULE_DIR$" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="imports" level="project" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../jmbe/jmbe/library/jmbe-0.3.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="org.asynchttpclient:async-http-client:2.0.18" level="project" />
</component>
</module>

1
settings.gradle Normal file
View File

@@ -0,0 +1 @@
rootProject.name = 'sdr-trunk'

View File

@@ -1,4 +0,0 @@
[Dolphin]
Timestamp=2015,9,1,6,42,59
Version=3
ViewMode=1

View File

@@ -1,354 +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 alias;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import alias.action.AliasAction;
import alias.id.AliasID;
import alias.id.AliasIDType;
import alias.id.broadcast.BroadcastChannel;
import alias.id.nonrecordable.NonRecordable;
import alias.id.priority.Priority;
@XmlSeeAlso( { AliasID.class, AliasAction.class } )
@XmlRootElement( name = "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>();
public Alias()
{
}
public Alias( String name )
{
mName = name;
}
public String toString()
{
return getName();
}
@XmlAttribute( name="name" )
public String getName()
{
return mName;
}
public void setName( String name )
{
mName = name;
}
@XmlAttribute( name="list" )
public String getList()
{
return mList;
}
public void setList( String list )
{
mList = list;
}
public boolean hasList()
{
return mList != null;
}
@XmlAttribute( name="group" )
public String getGroup()
{
return mGroup;
}
public void setGroup( String group )
{
mGroup = group;
}
public boolean hasGroup()
{
return mGroup != null;
}
@XmlAttribute
public int getColor()
{
return mColor;
}
public void setColor( int color )
{
mColor = color;
}
public Color getDisplayColor()
{
return new Color( getColor() );
}
@XmlAttribute
public String getIconName()
{
return mIconName;
}
public void setIconName( String iconName )
{
mIconName = iconName;
}
@XmlElement( name="id" )
public List<AliasID> getId()
{
return mAliasIDs;
}
public void setId( ArrayList<AliasID> id )
{
mAliasIDs = id;
}
public void addAliasID( AliasID id )
{
mAliasIDs.add( id );
}
public void removeAliasID( AliasID id )
{
mAliasIDs.remove( id );
}
@XmlElement( name="action" )
public List<AliasAction> getAction()
{
return mAliasActions;
}
public void setAction( List<AliasAction> actions )
{
mAliasActions = actions;
}
public void addAliasAction( AliasAction action )
{
mAliasActions.add( action );
}
public void removeAliasAction( AliasAction action )
{
mAliasActions.remove( action );
}
public boolean hasActions()
{
return !mAliasActions.isEmpty();
}
/**
* Perform any validation/cleanup actions on this alias.
*/
public void validate()
{
}
/**
* Returns the priority level of this alias, if defined, or the default priority
*/
@XmlTransient
public int getCallPriority()
{
for( AliasID id: mAliasIDs )
{
if( id.getType() == AliasIDType.PRIORITY)
{
return ((Priority)id).getPriority();
}
}
return Priority.DEFAULT_PRIORITY;
}
public boolean hasCallPriority()
{
for( AliasID id: mAliasIDs )
{
if( id.getType() == AliasIDType.PRIORITY)
{
return true;
}
}
return false;
}
/**
* Sets or updates the call priority
*/
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;
}
}
//If we don't find a priority id, create one
Priority p = new Priority();
p.setPriority( priority );
addAliasID( p );
}
}
/**
* Inspects the alias for a non-recordable alias id. Default is true;
*/
@XmlTransient
public boolean isRecordable()
{
for( AliasID id: getId() )
{
if( id.getType() == AliasIDType.NON_RECORDABLE)
{
return false;
}
}
return true;
}
/**
* Sets or removes the non-recordable alias ID for this alias.
*/
public void setRecordable( boolean recordable )
{
if( recordable )
{
AliasID toRemove = null;
for( AliasID id: getId() )
{
if( id.getType() == AliasIDType.NON_RECORDABLE)
{
toRemove = id;
break;
}
}
if( toRemove != null )
{
removeAliasID( toRemove );
}
}
else
{
for( AliasID id: getId() )
{
if( id.getType() == AliasIDType.NON_RECORDABLE)
{
return;
}
}
addAliasID( new NonRecordable() );
}
}
/**
* Inspects the alias for broadcast channel/streamable alias ids. Default is false;
*/
@XmlTransient
public boolean isStreamable()
{
for( AliasID id: getId() )
{
if( id.getType() == AliasIDType.BROADCAST_CHANNEL)
{
return true;
}
}
return false;
}
/**
* List of broadcast channels specified for this alias.
*/
@XmlTransient
public Set<BroadcastChannel> getBroadcastChannels()
{
Set<BroadcastChannel> broadcastChannels = new TreeSet<>();
for(AliasID id: getId())
{
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
{
broadcastChannels.add((BroadcastChannel)id);
}
}
return broadcastChannels;
}
/**
* Indicates if this alias contains a broadcast channel alias id with the channel name.
*/
public boolean hasBroadcastChannel(String channel)
{
if(channel == null || channel.isEmpty())
{
return false;
}
for(AliasID id: getId())
{
if(id.getType() == AliasIDType.BROADCAST_CHANNEL &&
((BroadcastChannel)id).getChannelName().contentEquals(channel))
{
return true;
}
}
return false;
}
}

View File

@@ -1,356 +0,0 @@
package alias;
import audio.broadcast.BroadcastModel;
import com.jidesoft.swing.JideSplitPane;
import gui.editor.Editor;
import 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,164 +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 alias;
import audio.broadcast.BroadcastModel;
import gui.editor.Editor;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import icon.IconManager;
import net.miginfocom.swing.MigLayout;
import sample.Listener;
import settings.SettingsManager;
import alias.action.AliasActionEditor;
import alias.id.AliasIdentifierEditor;
import com.jidesoft.swing.JideTabbedPane;
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 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 +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 alias;
import alias.action.AliasAction;
import alias.action.AliasActionType;
import alias.action.beep.BeepAction;
import alias.action.beep.BeepActionEditor;
import alias.action.clip.ClipAction;
import alias.action.clip.ClipActionEditor;
import alias.action.script.ScriptAction;
import alias.action.script.ScriptActionEditor;
import alias.id.AliasID;
import alias.id.AliasIDType;
import alias.id.broadcast.BroadcastChannel;
import alias.id.broadcast.BroadcastChannelEditor;
import alias.id.esn.ESNEditor;
import alias.id.esn.Esn;
import alias.id.fleetsync.FleetsyncID;
import alias.id.fleetsync.FleetsyncIDEditor;
import alias.id.lojack.LoJackFunctionAndID;
import alias.id.lojack.LoJackIDEditor;
import alias.id.mdc.MDC1200ID;
import alias.id.mdc.MDC1200IDEditor;
import alias.id.mobileID.MINEditor;
import alias.id.mobileID.Min;
import alias.id.mpt1327.MPT1327ID;
import alias.id.mpt1327.MPT1327IDEditor;
import alias.id.nonrecordable.NonRecordable;
import alias.id.nonrecordable.NonRecordableEditor;
import alias.id.priority.Priority;
import alias.id.priority.PriorityEditor;
import alias.id.siteID.SiteID;
import alias.id.siteID.SiteIDEditor;
import alias.id.status.StatusID;
import alias.id.status.StatusIDEditor;
import alias.id.talkgroup.TalkgroupID;
import alias.id.talkgroup.TalkgroupIDEditor;
import alias.id.uniqueID.UniqueID;
import alias.id.uniqueID.UniqueIDEditor;
import audio.broadcast.BroadcastModel;
import gui.editor.Editor;
import gui.editor.EmptyEditor;
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:
}
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 );
}
}
for( AliasAction action: original.getAction() )
{
AliasAction copyAction = copyOf( action );
if( copyAction != null )
{
copy.addAliasAction( copyAction );
}
}
return copy;
}
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 );
}
}
}

View File

@@ -1,677 +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 alias;
import alias.id.AliasID;
import alias.id.WildcardID;
import alias.id.esn.Esn;
import alias.id.fleetsync.FleetsyncID;
import alias.id.lojack.LoJackFunctionAndID;
import alias.id.mdc.MDC1200ID;
import alias.id.mobileID.Min;
import alias.id.mpt1327.MPT1327ID;
import alias.id.siteID.SiteID;
import alias.id.status.StatusID;
import alias.id.talkgroup.TalkgroupID;
import alias.id.uniqueID.UniqueID;
import module.decode.lj1200.LJ1200Message.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import javax.xml.bind.annotation.XmlAttribute;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AliasList implements Listener<AliasEvent>
{
private final static Logger mLog = LoggerFactory.getLogger(AliasList.class);
public static final String WILDCARD = "*";
public static final String REGEX_WILDCARD = ".";
private Map<String,Alias> mESN = new HashMap<>();
private Map<String,Alias> mFleetsync = new HashMap<>();
private Map<LoJackFunctionAndID,Alias> mLoJack = new HashMap<>();
private Map<String,Alias> mMDC1200 = new HashMap<>();
private Map<String,Alias> mMobileID = new HashMap<>();
private Map<String,Alias> mMPT1327 = new HashMap<>();
private Map<String,Alias> mSiteID = new HashMap<>();
private Map<Integer,Alias> mStatus = new HashMap<>();
private Map<String,Alias> mTalkgroup = new HashMap<>();
private Map<Integer,Alias> mUniqueID = new HashMap<>();
private List<WildcardID> mESNWildcards = new ArrayList<>();
private List<WildcardID> mMobileIDWildcards = new ArrayList<>();
private List<WildcardID> mFleetsyncWildcards = new ArrayList<>();
private List<WildcardID> mMDC1200Wildcards = new ArrayList<>();
private List<WildcardID> mMPT1327Wildcards = new ArrayList<>();
private List<WildcardID> mSiteWildcards = new ArrayList<>();
private List<WildcardID> mTalkgroupWildcards = new ArrayList<>();
private String mName;
/**
* List of aliases where all aliases share the same list name. Contains
* several methods for alias lookup from identifier values, like talkgroups.
*
* Responds to alias change events to keep the internal alias list updated.
*/
public AliasList(String name)
{
mName = name;
}
/**
* Adds the alias to this list
*/
public void addAlias(Alias alias)
{
if(alias != null)
{
for(AliasID aliasID : alias.getId())
{
addAliasID(aliasID, alias);
}
}
}
/**
* Adds the alias and alias identifier to the internal type mapping.
*/
private void addAliasID(AliasID id, Alias alias)
{
if(id.isValid())
{
try
{
switch(id.getType())
{
case ESN:
String esn = ((Esn) id).getEsn();
if(esn != null)
{
if(esn.contains(WILDCARD))
{
mESNWildcards.add(new WildcardID(esn));
Collections.sort(mESNWildcards);
}
mESN.put(esn, alias);
}
break;
case FLEETSYNC:
String fleetsync = ((FleetsyncID) id).getIdent();
if(fleetsync != null)
{
if(fleetsync.contains(WILDCARD))
{
mFleetsyncWildcards.add(new WildcardID(fleetsync));
Collections.sort(mFleetsyncWildcards);
}
mFleetsync.put(fleetsync, alias);
}
break;
case LOJACK:
mLoJack.put((LoJackFunctionAndID) id, alias);
break;
case MDC1200:
String mdc = ((MDC1200ID) id).getIdent();
if(mdc != null)
{
if(mdc.contains(WILDCARD))
{
mMDC1200Wildcards.add(new WildcardID(mdc));
Collections.sort(mMDC1200Wildcards);
}
mMDC1200.put(mdc, alias);
}
break;
case MPT1327:
String mpt = ((MPT1327ID) id).getIdent();
if(mpt != null)
{
if(mpt.contains(WILDCARD))
{
mMPT1327Wildcards.add(new WildcardID(mpt));
Collections.sort(mMPT1327Wildcards);
}
mMPT1327.put(mpt, alias);
}
break;
case MIN:
String min = ((Min) id).getMin();
if(min != null)
{
if(min.contains(WILDCARD))
{
mMobileIDWildcards.add(new WildcardID(min));
Collections.sort(mMobileIDWildcards);
}
mMobileID.put(min, alias);
}
break;
case LTR_NET_UID:
mUniqueID.put(((UniqueID) id).getUid(), alias);
break;
case SITE:
String siteID = ((SiteID) id).getSite();
if(siteID != null)
{
if(siteID.contains(WILDCARD))
{
mSiteWildcards.add(new WildcardID(siteID));
Collections.sort(mSiteWildcards);
}
mSiteID.put(siteID, alias);
}
break;
case STATUS:
mStatus.put(((StatusID) id).getStatus(), alias);
break;
case TALKGROUP:
String tgid = ((TalkgroupID) id).getTalkgroup();
if(tgid != null)
{
if(tgid.contains(WILDCARD))
{
mTalkgroupWildcards.add(new WildcardID(tgid));
Collections.sort(mTalkgroupWildcards);
}
mTalkgroup.put(tgid, alias);
}
break;
case BROADCAST_CHANNEL:
case NON_RECORDABLE:
case PRIORITY:
//We don't maintain lookups for these items
break;
default:
mLog.warn("Unrecognized Alias ID Type:" + id.getType().name() + " - can't ADD to lookup table");
break;
}
}
catch(Exception e)
{
mLog.error("Couldn't add alias ID " + id + " for alias " + alias);
}
}
}
/**
* Removes the alias from this list
*/
public void removeAlias(Alias alias)
{
if(alias != null)
{
for(AliasID aliasID : alias.getId())
{
removeAliasID(aliasID, alias);
}
}
}
private void removeWildcard(String value, List<WildcardID> wildcards)
{
if(value != null)
{
for(WildcardID wildcardID : wildcards)
{
if(wildcardID.value().equals(value))
{
wildcards.remove(wildcardID);
}
}
}
}
/**
* Removes the alias and alias identifier from internal mappings.
*/
private void removeAliasID(AliasID id, Alias alias)
{
if(id.isValid())
{
switch(id.getType())
{
case ESN:
String esn = ((Esn) id).getEsn();
if(esn != null)
{
if(esn.contains(WILDCARD))
{
removeWildcard(esn, mESNWildcards);
}
}
mESN.remove(esn);
break;
case FLEETSYNC:
String fleetsync = ((FleetsyncID) id).getIdent();
if(fleetsync != null)
{
if(fleetsync.contains(WILDCARD))
{
removeWildcard(fleetsync, mFleetsyncWildcards);
}
mFleetsync.remove(fleetsync);
}
break;
case LOJACK:
mLoJack.remove((LoJackFunctionAndID) id);
break;
case MDC1200:
String mdc = ((MDC1200ID) id).getIdent();
if(mdc != null)
{
if(mdc.contains(WILDCARD))
{
removeWildcard(mdc, mMDC1200Wildcards);
}
mMDC1200.remove(mdc);
}
break;
case MPT1327:
String mpt = ((MPT1327ID) id).getIdent();
if(mpt != null)
{
if(mpt.contains(WILDCARD))
{
removeWildcard(mpt, mMPT1327Wildcards);
}
mMPT1327.remove(mpt);
}
break;
case MIN:
String min = ((Min) id).getMin();
if(min != null)
{
if(min.contains(WILDCARD))
{
removeWildcard(min, mMobileIDWildcards);
}
mMobileID.remove(min);
}
break;
case LTR_NET_UID:
mUniqueID.remove(((UniqueID) id).getUid());
break;
case SITE:
mSiteID.remove(((SiteID) id).getSite());
break;
case STATUS:
mStatus.remove(((StatusID) id).getStatus());
break;
case TALKGROUP:
String tgid = ((TalkgroupID) id).getTalkgroup();
if(tgid != null)
{
if(tgid.contains(WILDCARD))
{
removeWildcard(tgid, mTalkgroupWildcards);
}
mTalkgroup.remove(tgid);
}
break;
case NON_RECORDABLE:
case PRIORITY:
case BROADCAST_CHANNEL:
//We don't maintain lookups for these items
break;
default:
mLog.warn("Unrecognized Alias ID Type:" + id.getType().name() + " - can't REMOVE from lookup table");
break;
}
}
}
/**
* Returns the first matching regex wildcard from the list of wildcards that matches the
* identifier.
*
* @param id to match
* @param wildcards to match against
* @return matching wildcard ID or null
*/
private String getWildcardMatch(String id, List<WildcardID> wildcards)
{
if(id != null)
{
for(WildcardID wildcard : wildcards)
{
if(wildcard.matches(id))
{
return wildcard.value();
}
}
}
return null;
}
/**
* Lookup alias by site ID
*/
public Alias getSiteID(String siteID)
{
Alias alias = null;
if(siteID != null)
{
alias = mSiteID.get(siteID);
if(alias == null)
{
String wildcard = getWildcardMatch(siteID, mSiteWildcards);
if(wildcard != null)
{
alias = mSiteID.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by status ID
*/
public Alias getStatus(int status)
{
return mStatus.get(status);
}
/**
* Lookup alias by Unique ID (UID)
*/
public Alias getUniqueID(int uniqueID)
{
return mUniqueID.get(uniqueID);
}
/**
* Lookup alias by ESN
*/
public Alias getESNAlias(String esn)
{
Alias alias = null;
if(esn != null)
{
alias = mESN.get(esn);
if(alias == null)
{
String wildcard = getWildcardMatch(esn, mESNWildcards);
if(wildcard != null)
{
alias = mESN.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by fleetsync ID
*/
public Alias getFleetsyncAlias(String ident)
{
Alias alias = null;
if(ident != null)
{
alias = mFleetsync.get(ident);
if(alias == null)
{
String wildcard = getWildcardMatch(ident, mFleetsyncWildcards);
if(wildcard != null)
{
alias = mFleetsync.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by lojack function and ID
*/
public Alias getLoJackAlias(Function function, String id)
{
if(id != null)
{
for(LoJackFunctionAndID lojack : mLoJack.keySet())
{
if(lojack.matches(function, id))
{
return mLoJack.get(lojack);
}
}
}
return null;
}
/**
* Lookup alias by MDC1200 ID
*/
public Alias getMDC1200Alias(String ident)
{
Alias alias = null;
if(ident != null)
{
alias = mMDC1200.get(ident);
if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMDC1200Wildcards);
if(wildcard != null)
{
alias = mMDC1200.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by MPT1327 Ident
*/
public Alias getMPT1327Alias(String ident)
{
Alias alias = null;
if(ident != null)
{
alias = mMPT1327.get(ident);
if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMPT1327Wildcards);
if(wildcard != null)
{
alias = mMPT1327.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by Mobile ID Number (MIN)
*/
public Alias getMobileIDNumberAlias(String ident)
{
Alias alias = null;
if(ident != null)
{
alias = mMobileID.get(ident);
if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMobileIDWildcards);
if(wildcard != null)
{
alias = mMobileID.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by talkgroup
*
* @param tgid to use when searching for an alias
* @param includeWildcards true if you want to additionally search for a matching alias that contains wildcard(s)
* when there is not a direct match to the TGID.
*/
public Alias getTalkgroupAlias(String tgid, boolean includeWildcards)
{
Alias alias = null;
if(tgid != null)
{
alias = mTalkgroup.get(tgid);
if(alias == null && includeWildcards)
{
String wildcard = getWildcardMatch(tgid, mTalkgroupWildcards);
if(wildcard != null)
{
alias = mTalkgroup.get(wildcard);
}
}
}
return alias;
}
/**
* Lookup alias by talkgroup. Defaults to matching to wildcard talkgroups.
*/
public Alias getTalkgroupAlias(String tgid)
{
return getTalkgroupAlias(tgid, true);
}
/**
* Alias list name
*/
public String toString()
{
return mName;
}
/**
* Alias list name
*/
@XmlAttribute
public String getName()
{
return mName;
}
/**
* Indicates if this alias list has a non-null, non-empty name
*/
private boolean hasName()
{
return mName != null && !mName.isEmpty();
}
/**
* Receive alias change event notifications and modify this list accordingly
*/
@Override
public void receive(AliasEvent event)
{
if(hasName())
{
Alias alias = event.getAlias();
switch(event.getEvent())
{
case ADD:
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
addAlias(alias);
}
break;
case CHANGE:
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
addAlias(alias);
}
break;
case DELETE:
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
removeAlias(alias);
}
break;
default:
break;
}
}
}
}

View File

@@ -1,350 +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 alias;
import alias.AliasEvent.Event;
import alias.id.broadcast.BroadcastChannel;
import sample.Broadcaster;
import sample.Listener;
import javax.swing.table.AbstractTableModel;
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;
/**
* Alias Model
*/
public class AliasModel extends AbstractTableModel
{
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 Map<String,AliasList> mAliasListMap = new HashMap<>();
public AliasModel()
{
}
/**
* Unmodifiable list of all aliases currently in the model
*/
public List<Alias> getAliases()
{
return Collections.unmodifiableList(mAliases);
}
public Alias getAliasAtIndex(int row)
{
if(mAliases.size() >= row)
{
return mAliases.get(row);
}
return null;
}
public AliasList getAliasList(String name)
{
if(name != null && mAliasListMap.containsKey(name))
{
return mAliasListMap.get(name);
}
AliasList aliasList = new AliasList(name);
if(name != null)
{
for(Alias alias : mAliases)
{
if(alias.hasList() && alias.getList().equalsIgnoreCase(name))
{
aliasList.addAlias(alias);
}
}
mAliasListMap.put(name, aliasList);
//Register the new alias list to receive updates from this model
addListener(aliasList);
}
return aliasList;
}
/**
* Returns a list of unique alias list names from across the alias set
*/
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;
}
/**
* Returns a list of alias group names for all aliases
*/
public List<String> getGroupNames()
{
List<String> groupNames = new ArrayList<>();
for(Alias alias : mAliases)
{
if(alias.hasGroup() && !groupNames.contains(alias.getGroup()))
{
groupNames.add(alias.getGroup());
}
}
Collections.sort(groupNames);
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);
}
}
/**
* Adds the alias to the model
*/
public int addAlias(Alias alias)
{
if(alias != null)
{
mAliases.add(alias);
int index = mAliases.size() - 1;
fireTableRowsInserted(index, index);
broadcast(new AliasEvent(alias, Event.ADD));
return index;
}
return -1;
}
/**
* Removes the channel from the model and broadcasts a channel remove event
*/
public void removeAlias(Alias alias)
{
if(alias != null)
{
int index = mAliases.indexOf(alias);
mAliases.remove(alias);
fireTableRowsDeleted(index, index);
broadcast(new AliasEvent(alias, Event.DELETE));
}
}
/**
* Renames any broadcast channels that have the previous name.
*
* @param previousName to rename
* @param newName to assign to the broadcast channel
*/
public void renameBroadcastChannel(String previousName, String newName)
{
if(previousName == null || previousName.isEmpty() || newName == null || newName.isEmpty())
{
return;
}
for(Alias alias : mAliases)
{
if(alias.hasBroadcastChannel(previousName))
{
for(BroadcastChannel broadcastChannel : alias.getBroadcastChannels())
{
if(broadcastChannel.getChannelName().contentEquals(previousName))
{
broadcastChannel.setChannelName(newName);
}
}
}
}
}
@Override
public int getRowCount()
{
return mAliases.size();
}
@Override
public int getColumnCount()
{
return 5;
}
@Override
public String getColumnName(int columnIndex)
{
switch(columnIndex)
{
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";
}
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() == 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,334 +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 alias;
import alias.AliasEvent.Event;
import gui.editor.Editor;
import icon.Icon;
import icon.IconListCellRenderer;
import icon.IconManager;
import 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(), 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 alias;
import javax.swing.JPanel;
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 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,467 +0,0 @@
package alias;
import alias.AliasEvent.Event;
import alias.id.AliasIDType;
import alias.id.broadcast.BroadcastChannel;
import alias.id.priority.Priority;
import audio.broadcast.BroadcastModel;
import gui.editor.Editor;
import icon.Icon;
import icon.IconListCellRenderer;
import icon.IconManager;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
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, Event.CHANGE));
}
}
}
@Override
public void receive(AliasEvent event)
{
if (event.getEvent() == 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,381 +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 alias;
import alias.action.AliasAction;
import alias.id.AliasID;
import alias.id.AliasIDType;
import alias.id.broadcast.BroadcastChannel;
import alias.id.priority.Priority;
import alias.id.talkgroup.TalkgroupID;
import gui.SDRTrunk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import playlist.version1.System;
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

@@ -1,58 +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 alias.action;
import alias.Alias;
import alias.action.beep.BeepAction;
import alias.action.clip.ClipAction;
import alias.action.script.ScriptAction;
import message.Message;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import java.util.concurrent.ScheduledExecutorService;
/**
* Alias action defines an action to execute when an alias is detected active.
*/
@XmlSeeAlso( { BeepAction.class, ClipAction.class, ScriptAction.class } )
@XmlRootElement( name = "action" )
public abstract class AliasAction
{
public AliasAction()
{
}
@XmlTransient
public abstract AliasActionType getType();
/**
* Task to execute when an alias action is defined. The message argument is
* the original message containing one or more aliases that have an alias
* action attached. The alias argument is the parent alias containing the
* alias action.
*/
public abstract void execute( ScheduledExecutorService scheduledExecutorService, Alias alias, Message message );
/**
* Dismiss a persistent alias action
*/
public abstract void dismiss( boolean reset );
}

View File

@@ -1,350 +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 alias.action;
import gui.editor.Editor;
import gui.editor.EmptyEditor;
import java.awt.EventQueue;
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;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import alias.Alias;
import alias.AliasEvent;
import alias.AliasEvent.Event;
import alias.AliasFactory;
import alias.AliasModel;
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 alias.action;
import 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 +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 alias.action;
import alias.Alias;
import message.Message;
import sample.Listener;
import util.ThreadPool;
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.
*
* 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 AliasActionManager()
{
}
@Override
public void receive(Message message)
{
if(message.isValid())
{
List<Alias> aliases = message.getAliases();
if(aliases != null)
{
for(Alias alias : aliases)
{
if(alias.hasActions())
{
List<AliasAction> actions = alias.getAction();
for(AliasAction action : actions)
{
/* 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);
}
}
}
}
}
}
}

View File

@@ -1,181 +0,0 @@
package alias.action;
import alias.Alias;
import message.Message;
import javax.swing.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import java.awt.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class RecurringAction extends AliasAction
{
@XmlTransient
protected AtomicBoolean mRunning = new AtomicBoolean(false);
@XmlTransient
private ScheduledFuture<?> mPerpetualAction;
@XmlTransient
protected ScheduledExecutorService mScheduledExecutorService;
protected Interval mInterval = Interval.ONCE;
protected int mPeriod = 5;
public abstract void performAction(Alias alias, Message message);
@Override
public void execute(ScheduledExecutorService scheduledExecutorService, Alias alias, Message message)
{
mScheduledExecutorService = scheduledExecutorService;
if(mRunning.compareAndSet(false, true))
{
switch(mInterval)
{
case ONCE:
performThreadedAction(alias, message);
/* Don't reset */
break;
case DELAYED_RESET:
performThreadedAction(alias, message);
mScheduledExecutorService.schedule(new ResetTask(), mPeriod, TimeUnit.SECONDS);
break;
case UNTIL_DISMISSED:
mPerpetualAction = mScheduledExecutorService.scheduleAtFixedRate(
new PerformActionTask(alias, message), mPeriod, mPeriod, TimeUnit.SECONDS);
StringBuilder sb = new StringBuilder();
sb.append("<html><div width='250'>Alias [");
sb.append(alias.getName());
sb.append("] is active in message [");
sb.append(message.toString());
sb.append("]</div></html>");
final String text = sb.toString();
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
JOptionPane.showMessageDialog(null, text,
"Alias Alert", JOptionPane.INFORMATION_MESSAGE);
dismiss(false);
mScheduledExecutorService.schedule(new ResetTask(), 15, TimeUnit.SECONDS);
}
});
break;
default:
}
}
}
/**
* 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)
{
mScheduledExecutorService.schedule(new Runnable()
{
@Override
public void run()
{
performAction(alias, message);
}
}, 0, TimeUnit.SECONDS);
}
@Override
public void dismiss(boolean reset)
{
if(mPerpetualAction != null)
{
mPerpetualAction.cancel(true);
mPerpetualAction = null;
}
if(reset)
{
mRunning.set(false);
}
}
@XmlAttribute
public int getPeriod()
{
return mPeriod;
}
public void setPeriod(int period)
{
mPeriod = period;
}
@XmlAttribute
public Interval getInterval()
{
return mInterval;
}
public void setInterval(Interval interval)
{
mInterval = interval;
mRunning.set(false);
}
public enum Interval
{
ONCE("Once"),
DELAYED_RESET("Once, Reset After Delay"),
UNTIL_DISMISSED("Until Dismissed");
private String mLabel;
private Interval(String label)
{
mLabel = label;
}
public String toString()
{
return mLabel;
}
}
public class PerformActionTask implements Runnable
{
private Alias mAlias;
private Message mMessage;
public PerformActionTask(Alias alias, Message message)
{
mAlias = alias;
mMessage = message;
}
@Override
public void run()
{
/* Don't use the performThreadedAction() method, since this is
* already running in a separate thread */
performAction(mAlias, mMessage);
}
}
public class ResetTask implements Runnable
{
@Override
public void run()
{
mRunning.set(false);
}
}
}

View File

@@ -1,28 +0,0 @@
package alias.action.beep;
import message.Message;
import alias.Alias;
import alias.action.AliasActionType;
import alias.action.RecurringAction;
public class BeepAction extends RecurringAction
{
@Override
public AliasActionType getType()
{
return AliasActionType.BEEP;
}
@Override
public void performAction( Alias alias, Message message )
{
System.out.println( "\007" );
}
@Override
public String toString()
{
return "Beep";
}
}

View File

@@ -1,193 +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 alias.action.beep;
import gui.editor.DocumentListenerEditor;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import alias.action.AliasAction;
import alias.action.RecurringAction.Interval;
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<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<Interval>( Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period spinner based on selection */
boolean enabled = selected != 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();
Interval interval = beep.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != 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( (Interval)mComboInterval.getSelectedItem() );
beep.setPeriod( mPeriodSlider.getValue() );
}
setModified( false );
}
}

View File

@@ -1,110 +0,0 @@
package alias.action.clip;
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.xml.bind.annotation.XmlTransient;
import message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.Alias;
import alias.action.AliasActionType;
import alias.action.RecurringAction;
public class ClipAction extends RecurringAction
{
private final static Logger mLog = LoggerFactory.getLogger( ClipAction.class );
private String mFilePath;
@XmlTransient
private Clip mClip;
public ClipAction()
{
}
@Override
public AliasActionType getType()
{
return AliasActionType.CLIP;
}
public String getPath()
{
return mFilePath;
}
public void setPath( String path )
{
mFilePath = path;
}
@Override
public void performAction( Alias alias, Message message )
{
try
{
play();
}
catch( Exception e )
{
mLog.error( "Couldn't play audio clip", e );
}
}
public void play() throws Exception
{
try
{
if( mFilePath != null )
{
if( mClip == null )
{
mClip = AudioSystem.getClip();
AudioInputStream ais =
AudioSystem.getAudioInputStream( new File( mFilePath ) );
mClip.open( ais );
}
if( mClip.isRunning() )
{
mClip.stop();
}
mClip.setFramePosition( 0 );
mClip.start();
}
}
catch( Exception e )
{
mClip = null;
mLog.error( "Error playing sound clip [" + mFilePath + "] - " + e.getMessage() );
throw e;
}
}
@Override
public String toString()
{
if( mFilePath == null )
{
return "Play Clip";
}
else
{
return "Play Clip: " + mFilePath;
}
}
}

View File

@@ -1,296 +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 alias.action.clip;
import gui.editor.DocumentListenerEditor;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import alias.action.AliasAction;
import alias.action.RecurringAction.Interval;
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<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<Interval>( Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period slider based on selection */
boolean enabled = selected != 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();
Interval interval = clip.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != 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( (Interval)mComboInterval.getSelectedItem() );
script.setPeriod( mPeriodSlider.getValue() );
script.setPath( mTextFilePath.getText() );
}
setModified( false );
}
}

View File

@@ -1,98 +0,0 @@
package alias.action.script;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.Alias;
import alias.action.AliasActionType;
import alias.action.RecurringAction;
public class ScriptAction extends RecurringAction
{
private final static Logger mLog = LoggerFactory.getLogger( ScriptAction.class );
private String mScript;
public ScriptAction()
{
}
@Override
public AliasActionType getType()
{
return AliasActionType.SCRIPT;
}
public String getScript()
{
return mScript;
}
public void setScript( String script )
{
mScript = script;
}
@Override
public void performAction( Alias alias, Message message )
{
try
{
play();
}
catch( Exception e )
{
mLog.error( "Couldn't execute script [" + mScript + "]", e );
}
}
public void play() throws Exception
{
if( mScript != null )
{
ProcessBuilder pb = new ProcessBuilder( mScript );
pb.redirectErrorStream( true );
Process p = pb.start();
int exitCode = p.waitFor();
BufferedReader reader = new BufferedReader(
new InputStreamReader( p.getInputStream() ) );
String line = "";
StringBuilder sb = new StringBuilder();
while( ( line = reader.readLine() ) != null )
{
sb.append(line + "\n");
}
if( exitCode != 0 )
{
throw new RuntimeException( "Exit Code: " + exitCode +
" Console:" + sb.toString() );
}
}
}
@Override
public String toString()
{
if( mScript == null )
{
return "Run Script";
}
else
{
return "Run Script: " + mScript;
}
}
}

View File

@@ -1,292 +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 alias.action.script;
import gui.editor.DocumentListenerEditor;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import alias.action.AliasAction;
import alias.action.RecurringAction.Interval;
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<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<Interval>( Interval.values() );
mComboInterval.setToolTipText( HELP_TEXT );
mComboInterval.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Interval selected = mComboInterval
.getItemAt( mComboInterval.getSelectedIndex() );
if( selected != null )
{
/* Enable/disable period slider based on selection */
boolean enabled = selected != 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();
Interval interval = script.getInterval();
mComboInterval.setSelectedItem( interval );
boolean enabled = interval != 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( (Interval)mComboInterval.getSelectedItem() );
script.setPeriod( mPeriodSlider.getValue() );
script.setScript( mTextFilePath.getText() );
}
setModified( false );
}
}

View File

@@ -1,57 +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 alias.id;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import alias.id.broadcast.BroadcastChannel;
import playlist.version1.Group;
import alias.id.esn.Esn;
import alias.id.fleetsync.FleetsyncID;
import alias.id.lojack.LoJackFunctionAndID;
import alias.id.mdc.MDC1200ID;
import alias.id.mobileID.Min;
import alias.id.mpt1327.MPT1327ID;
import alias.id.nonrecordable.NonRecordable;
import alias.id.priority.Priority;
import alias.id.siteID.SiteID;
import alias.id.status.StatusID;
import alias.id.talkgroup.TalkgroupID;
import alias.id.uniqueID.UniqueID;
@SuppressWarnings( "deprecation" )
@XmlSeeAlso( {BroadcastChannel.class, Esn.class, FleetsyncID.class, Group.class, LoJackFunctionAndID.class,
MDC1200ID.class, Min.class, MPT1327ID.class, NonRecordable.class,
Priority.class, SiteID.class, StatusID.class, TalkgroupID.class,
UniqueID.class } )
@XmlRootElement( name = "id" )
public abstract class AliasID
{
public AliasID()
{
}
public abstract AliasIDType getType();
public abstract boolean matches( AliasID id );
@XmlTransient
public abstract boolean isValid();
}

View File

@@ -1,49 +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 alias.id;
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" ),
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;
}
}

View File

@@ -1,379 +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 alias.id;
import audio.broadcast.BroadcastModel;
import gui.editor.Editor;
import gui.editor.EmptyEditor;
import java.awt.EventQueue;
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;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import alias.Alias;
import alias.AliasEvent;
import alias.AliasEvent.Event;
import alias.AliasFactory;
import alias.AliasModel;
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, 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(), 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 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,130 +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 alias.id.broadcast;
import alias.id.AliasID;
import alias.id.AliasIDType;
import javax.xml.bind.annotation.XmlAttribute;
public class BroadcastChannel extends AliasID implements Comparable<BroadcastChannel>
{
private String mChannelName;
public BroadcastChannel()
{
//JAXB Constructor
}
@Override
public int compareTo(BroadcastChannel other)
{
if(mChannelName != null && other.getChannelName() != null)
{
return mChannelName.compareTo(other.getChannelName());
}
else if(mChannelName != null)
{
return -1;
}
else
{
return 1;
}
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(!(o instanceof BroadcastChannel))
{
return false;
}
BroadcastChannel that = (BroadcastChannel)o;
return getChannelName() != null ? getChannelName().equals(that.getChannelName()) : that.getChannelName() == null;
}
@Override
public int hashCode()
{
return getChannelName() != null ? getChannelName().hashCode() : 0;
}
/**
* Creates a named broadcast channel
*/
public BroadcastChannel(String channelName)
{
mChannelName = channelName;
}
/**
* Name of the broadcastAudio channel configuration
*/
@XmlAttribute(name = "channel")
public String getChannelName()
{
return mChannelName;
}
/**
* Sets the name of the broadcastAudio channel configuration
*/
public void setChannelName(String channel)
{
mChannelName = channel;
}
@Override
public AliasIDType getType()
{
return AliasIDType.BROADCAST_CHANNEL;
}
@Override
public boolean isValid()
{
return mChannelName != null;
}
@Override
public boolean matches(AliasID id)
{
return false;
}
@Override
public String toString()
{
if(isValid())
{
return "Broadcast Channel: " + mChannelName;
}
else
{
return "Broadcast Channel: None Selected";
}
}
}

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 alias.id.broadcast;
import alias.id.AliasID;
import audio.broadcast.BroadcastConfiguration;
import audio.broadcast.BroadcastModel;
import 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);
}
}
}

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