diff --git a/package.nw/GridTracker.html b/package.nw/GridTracker.html index 757e41f..db5aa74 100644 --- a/package.nw/GridTracker.html +++ b/package.nw/GridTracker.html @@ -60,6 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + @@ -2073,9 +2074,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
@@ -2438,7 +2436,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Source/Sync
-
+ +

Other Services

+ + + + + + + + + + + +
ServiceActive?Details
CatRotator / PstRotator + + + + + + +
+
@@ -3154,4 +3178,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- \ No newline at end of file + diff --git a/package.nw/gt_roster.html b/package.nw/gt_roster.html index ec2e639..cb3aa45 100644 --- a/package.nw/gt_roster.html +++ b/package.nw/gt_roster.html @@ -433,4 +433,4 @@
- \ No newline at end of file + diff --git a/package.nw/i18n/cn-t.json b/package.nw/i18n/cn-t.json index 5b70604..7ea346b 100644 --- a/package.nw/i18n/cn-t.json +++ b/package.nw/i18n/cn-t.json @@ -344,6 +344,13 @@ "settings.logging.HRDLogbook.source": "HRD Logbook", "settings.logging.HRDLogbook.details.IP": "IP地址", "settings.logging.HRDLogbook.details.Port": "埠號", + "settings.logging.other.title": "Other Services", + "settings.logging.otherheader.service": "Service", + "settings.logging.otherheader.active": "Active?", + "settings.logging.otherheader.details": "Details", + "settings.logging.pstrotator.label": "CatRotator / PstRotator", + "settings.logging.pstrotator.details.IP": "IP", + "settings.logging.pstrotator.details.Port": "UDP Port", "settings.callroster.AlwaysOnTop.label": "視窗始終在最上層", "settings.callroster.AlwaysOnTop.hover": "將呼叫清單置於其他視窗之上", "settings.callroster.MaxAge.label": "呼叫清單最大時效", @@ -995,6 +1002,7 @@ "roster.menu.RosterMode": "Roster Mode", "roster.menu.Lookup": "Lookup", "roster.menu.GenMesg": "Gen Msgs", + "roster.menu.AimRotator": "Aim Rotator", "roster.menu.IgnoreCall": "Ignore Call", "roster.menu.Realtime": "Realtime", "roster.menu.MoveLeft": "Move Column Left", @@ -1057,4 +1065,4 @@ "COMMENT_sendAlerts.js": "", "sendAlerts.scriptEnabled": "Script Enabled", "sendAlerts.scriptDisabled": "Script Disabled" -} \ No newline at end of file +} diff --git a/package.nw/i18n/cn.json b/package.nw/i18n/cn.json index 28a5dbe..e0a47d9 100644 --- a/package.nw/i18n/cn.json +++ b/package.nw/i18n/cn.json @@ -344,6 +344,13 @@ "settings.logging.HRDLogbook.source": "HRD Logbook", "settings.logging.HRDLogbook.details.IP": "IP地址", "settings.logging.HRDLogbook.details.Port": "端口", + "settings.logging.other.title": "Other Services", + "settings.logging.otherheader.service": "Service", + "settings.logging.otherheader.active": "Active?", + "settings.logging.otherheader.details": "Details", + "settings.logging.pstrotator.label": "CatRotator / PstRotator", + "settings.logging.pstrotator.details.IP": "IP", + "settings.logging.pstrotator.details.Port": "UDP Port", "settings.callroster.AlwaysOnTop.label": "窗口始终在最上层", "settings.callroster.AlwaysOnTop.hover": "将呼叫列表置于其他窗口之上", "settings.callroster.MaxAge.label": "呼叫列表最大时效", @@ -995,6 +1002,7 @@ "roster.menu.RosterMode": "Roster Mode", "roster.menu.Lookup": "Lookup", "roster.menu.GenMesg": "Gen Msgs", + "roster.menu.AimRotator": "Aim Rotator", "roster.menu.IgnoreCall": "Ignore Call", "roster.menu.Realtime": "Realtime", "roster.menu.MoveLeft": "Move Column Left", @@ -1057,4 +1065,4 @@ "COMMENT_sendAlerts.js": "", "sendAlerts.scriptEnabled": "Script Enabled", "sendAlerts.scriptDisabled": "Script Disabled" -} \ No newline at end of file +} diff --git a/package.nw/i18n/en.json b/package.nw/i18n/en.json index 48771a4..0c0c224 100644 --- a/package.nw/i18n/en.json +++ b/package.nw/i18n/en.json @@ -343,6 +343,13 @@ "settings.logging.HRDLogbook.source": "HRD Logbook", "settings.logging.HRDLogbook.details.IP": "IP", "settings.logging.HRDLogbook.details.Port": "Port", + "settings.logging.other.title": "Other Services", + "settings.logging.otherheader.service": "Service", + "settings.logging.otherheader.active": "Active?", + "settings.logging.otherheader.details": "Details", + "settings.logging.pstrotator.label": "CatRotator / PstRotator", + "settings.logging.pstrotator.details.IP": "IP", + "settings.logging.pstrotator.details.Port": "UDP Port", "settings.callroster.AlwaysOnTop.label": "Window Always On Top", "settings.callroster.AlwaysOnTop.hover": "Keep Call Roster Above Other Windows", "settings.callroster.MaxAge.label": "Call Roster Max Age", @@ -497,7 +504,7 @@ "roster.controls.hunting.label": "Hunting", "roster.controls.hunting.callsign": "Callsign", "roster.controls.hunting.grid": "Grid", - "roster.controls.hunting.dxcc": "DXCC", + "roster.controls.hunting.dxcc": "DXCC", "roster.controls.hunting.dxccSingle": "DXCC (Single)", "roster.controls.hunting.cqZone": "CQ Zone", "roster.controls.hunting.ituZone": "ITU Zone", @@ -544,7 +551,7 @@ "roster.secondary.exceptions.usesOQRS": "Uses OQRS", "roster.secondary.exceptions.wantRRCQ": "RR73 as CQ", "roster.secondary.exceptions.allOnlyNew": "Only New Calls", - "roster.secondary.exceptions.noMsg.label": "No", + "roster.secondary.exceptions.noMsg.label": "No", "roster.secondary.exceptions.noMsg.hover": "No Decodes Containing...", "roster.secondary.exceptions.onlyMsg.label": "Only", "roster.secondary.exceptions.onlyMsg.hover": "Only Decodes Containing...", @@ -995,6 +1002,7 @@ "roster.menu.RosterMode": "Roster Mode", "roster.menu.Lookup": "Lookup", "roster.menu.GenMesg": "Gen Msgs", + "roster.menu.AimRotator": "Aim Rotator", "roster.menu.IgnoreCall": "Ignore Call", "roster.menu.Realtime": "Realtime", "roster.menu.MoveLeft": "Move Column Left", @@ -1058,4 +1066,4 @@ "COMMENT_sendAlerts.js": "", "sendAlerts.scriptEnabled": "Script Enabled", "sendAlerts.scriptDisabled": "Script Disabled" -} \ No newline at end of file +} diff --git a/package.nw/lib/defaults.js b/package.nw/lib/defaults.js index 4b457c5..ea12543 100644 --- a/package.nw/lib/defaults.js +++ b/package.nw/lib/defaults.js @@ -27,7 +27,8 @@ var validSettings = [ "startupLogs", "trustedQslSettings", "screenSettings", - "legendColors" + "legendColors", + "pstrotatorSettings" ]; var def_appSettings = { @@ -234,7 +235,6 @@ var def_HRDLogbookLogSettings = { port: 7826, ip: "127.0.0.1" }; - var def_acLogSettings = { enable: false, port: 1100, @@ -277,3 +277,9 @@ var def_legendColors = { QRZ: "#FFFF00", QTH: "#FFA600" }; + +var def_pstrotatorSettings = { + enable: false, + port: 12000, + ip: "127.0.0.1" +}; diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index 1665cbc..f624f70 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -144,6 +144,10 @@ function loadAllSettings() "HRDLogbookLogSettings", def_HRDLogbookLogSettings ); + g_pstrotatorSettings = loadDefaultsAndMerge( + "pstrotatorSettings", + def_pstrotatorSettings + ); g_acLogSettings = loadDefaultsAndMerge("acLogSettings", def_acLogSettings); g_trustedQslSettings = loadDefaultsAndMerge( "trustedQslSettings", @@ -262,6 +266,7 @@ function saveLogSettings() localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings); localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings); localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings); + localStorage.pstrotatorSettings = JSON.stringify(g_pstrotatorSettings); localStorage.acLogSettings = JSON.stringify(g_acLogSettings); localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); } @@ -1077,7 +1082,7 @@ function addDeDx( var qsoDate = new Date(1970, 0, 1); qsoDate.setSeconds(finalTime); var isCurrentYear = (qsoDate.getFullYear() == currentYear); var dayAsString = String(parseInt(finalTime / 86400)); - + var callsign = null; var rect = null; var worked = false; @@ -1349,7 +1354,7 @@ function addDeDx( g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + band + "ph"] = true; } } - + worked = true; locked = true; details.worked = worked; @@ -5531,7 +5536,7 @@ function initMap() { var saveSettings = false; g_maps = Object.keys(g_maps).sort().reduce((obj, key) => { obj[key] = g_maps[key]; return obj; }, {}); - + if (!(g_mapSettings.mapIndex in g_maps)) { g_mapSettings.mapIndex = def_mapSettings.mapIndex; @@ -5745,7 +5750,7 @@ function initMap() noFeature = true; break; } - + if (features[index].size == 6) { noFeature = false; @@ -10627,7 +10632,7 @@ function redrawGrids() ~~g_cqZones[cqz].confirmed_modes[mode] + 1; } } - + if (ituz && ituz.length > 0) { if (g_ituZones[ituz].worked == false) @@ -10653,7 +10658,7 @@ function redrawGrids() ~~g_ituZones[ituz].confirmed_modes[mode] + 1; } } - + if (finalGrid.length > 0) { var gridCheck = finalGrid.substr(0, 4); @@ -12289,7 +12294,7 @@ function toggleTimezones() g_timezoneLayer = null; } } - + timezoneImg.style.filter = g_timezonesEnable == 1 ? "" : "grayscale(1)"; } @@ -12735,7 +12740,7 @@ function loadMapSettings() rosterDelayOnFocus.checked = g_appSettings.rosterDelayOnFocus; rosterDelayTime.value = g_appSettings.rosterDelayTime; rosterDelayTimeTd.innerHTML = rosterDelayTime.value + "ms"; - + setStrikesButton(); trafficDecode.checked = g_mapSettings.trafficDecode; @@ -13200,6 +13205,12 @@ function loadViewSettings() ValidatePort(hrdLogbookPortInput, buttonHrdLogbookCheckBox, null); ValidateIPaddress(hrdLogbookIpInput, buttonHrdLogbookCheckBox, null); + pstrotatorIpInput.value = g_pstrotatorSettings.ip; + pstrotatorPortInput.value = g_pstrotatorSettings.port; + pstrotatorCheckBox.checked = g_pstrotatorSettings.enable; + ValidatePort(pstrotatorPortInput, pstrotatorCheckBox, null); + ValidateIPaddress(pstrotatorIpInput, pstrotatorCheckBox, null); + spotHistoryTimeValue.value = parseInt( g_receptionSettings.viewHistoryTimeSec / 60 ); @@ -13506,7 +13517,7 @@ function postInit() openCallRosterWindow(false); openConditionsWindow(false); showMessaging(false); - + if (g_developerMode) { devPanel.style.display = "inline-block"; @@ -15719,7 +15730,7 @@ function mediaCheck() g_tracker.worked.px = {}; g_tracker.confirmed.px = {}; } - + if (typeof g_tracker.worked.pota == "undefined") { g_tracker.worked.pota = {}; @@ -15741,12 +15752,12 @@ function mediaCheck() g_QSOhash[i].px = null; } } - + if (typeof g_QSOhash[i].pota == "undefined" || g_QSOhash[i].pota == null) { g_QSOhash[i].pota = []; } - + g_QSOcount++; if (g_QSOhash[i].confirmed) g_QSLcount++; } diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index e512d1c..7bf5cf9 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -1725,13 +1725,28 @@ function addControls() callGenMessage(g_targetHash, ""); } }); - g_callMenu.append(item); item = new nw.MenuItem({ type: "separator" }); - g_callMenu.append(item); + if (window.opener.g_pstrotatorSettings.enable) + { + item = new nw.MenuItem({ + type: "normal", + label: $.i18n("roster.menu.AimRotator"), + click: function () + { + let target = callRoster[g_targetHash] + window.opener.aimRotator(target, ""); + } + }); + g_callMenu.append(item); + + item = new nw.MenuItem({ type: "separator" }); + g_callMenu.append(item); + } + item = new nw.MenuItem({ type: "normal", label: $.i18n("roster.menu.IgnoreCall"), @@ -1747,7 +1762,6 @@ function addControls() g_callMenu.append(item); g_callingMenu = new nw.Menu(); - item = new nw.MenuItem({ type: "normal", label: $.i18n("roster.menu.Lookup"), @@ -1773,6 +1787,23 @@ function addControls() item = new nw.MenuItem({ type: "separator" }); g_menu.append(item); + if (window.opener.g_pstrotatorSettings.enable) + { + item = new nw.MenuItem({ + type: "normal", + label: $.i18n("roster.menu.AimRotator"), + click: function () + { + let target = callRoster[g_targetHash] + window.opener.aimRotator(target, ""); + } + }); + g_callingMenu.append(item); + + item = new nw.MenuItem({ type: "separator" }); + g_callingMenu.append(item); + } + item = new nw.MenuItem({ type: "checkbox", label: $.i18n("roster.menu.Realtime"), diff --git a/package.nw/lib/services/pstrotator.js b/package.nw/lib/services/pstrotator.js new file mode 100644 index 0000000..63c26e4 --- /dev/null +++ b/package.nw/lib/services/pstrotator.js @@ -0,0 +1,82 @@ +/** + * PSTRotator is a third party application (windows-only) that interfaces with dozens of antenna rotators. + * It offers a way for other apps to request rotation to a specific azimuth, or a grid square. + * + * Other rotator control apps, like [CatRotator](https://www.pianetaradio.it/blog/catrotator/) also support this API. + * + * The most comprehensive API details are in this Groups.io post: + * https://groups.io/g/PstRotator/message/5825 + * + */ +var g_pstrotatorSettings = {}; + +function pstrotatorServiceChanged() +{ + if (g_pstrotatorSettings.enabled != pstrotatorCheckBox.checked) + { + // This setting toggles the presence of a contextual menu item in the roster, + // which is constructed only during roster initialization. + // + // So when this setting is changed, we need to reload the entire roster window. + // + g_pstrotatorSettings.enable = pstrotatorCheckBox.checked; + if (g_rosterInitialized) + { + try + { + g_callRosterWindowHandle.window.location.reload(); + } + catch (e) + { + console.error(e); + } + } + } + + g_pstrotatorSettings.ip = pstrotatorIpInput.value; + g_pstrotatorSettings.port = pstrotatorPortInput.value; + + saveLogSettings(); +} + +function aimRotator(info) +{ + const { callObj } = info + + if ( + g_pstrotatorSettings.enable == true && + g_pstrotatorSettings.port > 0 && + g_pstrotatorSettings.ip.length > 4 && + (callObj.distance > 0 || callObj.grid) + ) + { + let payload = "" + + if (callObj.distance > 0) + { + payload += `${Math.round(callObj.heading)}` + } + + if (callObj.grid) + { + payload += `${callObj.grid}` + } + + payload += "" + + try + { + sendUdpMessage( + payload, + payload.length, + parseInt(g_pstrotatorSettings.port), + g_pstrotatorSettings.ip + ); + addLastTraffic(`Aiming rotator towards ${data.DEcall}`); + } + catch (e) + { + addLastTraffic("UDP aimRotator failed"); + } + } +} diff --git a/package.nw/lib/style.css b/package.nw/lib/style.css index 9311610..f9ae2ee 100644 --- a/package.nw/lib/style.css +++ b/package.nw/lib/style.css @@ -619,7 +619,8 @@ a { margin: 0; display: none; background-color: black; - padding: 2px; + padding: 6px; + padding-bottom: 10px; text-align: center; width: auto; border: 1px solid blue; @@ -627,7 +628,8 @@ a { vertical-align: top; -webkit-border-radius: 6px; white-space: normal; - + max-height: 600px; + overflow: auto; /* animation: fadeEffect .3s; Fading effect takes 1 second */ }