v2: Deep Space Network view !22
8 files changed, +448 −1
Layout: unified · split
App/Sources/DSNSection.swift added +71
| @@ -0,0 +1,71 @@ | ||
| 1 | import Feeds | |
| 2 | import SwiftUI | |
| 3 | ||
| 4 | /// Which Deep Space Network dishes are talking to which spacecraft right now. | |
| 5 | struct DSNSection: View { | |
| 6 | var ink: Color | |
| 7 | var accent: Color | |
| 8 | @State private var status: DSNStatus? | |
| 9 | @State private var failed = false | |
| 10 | ||
| 11 | private var activeDishes: [DSNStatus.Dish] { | |
| 12 | status?.dishes.filter { !$0.links.isEmpty } ?? [] | |
| 13 | } | |
| 14 | ||
| 15 | var body: some View { | |
| 16 | VStack(alignment: .leading, spacing: 10) { | |
| 17 | Text("Deep Space Network now").font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).dimmed(0.6) | |
| 18 | if let status { | |
| 19 | ForEach(["Goldstone", "Madrid", "Canberra"], id: \.self) { station in | |
| 20 | let dishes = activeDishes.filter { $0.station == station } | |
| 21 | VStack(alignment: .leading, spacing: 4) { | |
| 22 | Text(station).font(.subheadline.weight(.medium)) | |
| 23 | if dishes.isEmpty { | |
| 24 | Text("No spacecraft in contact").font(.footnote).dimmed(0.6) | |
| 25 | } | |
| 26 | ForEach(dishes) { dish in | |
| 27 | ForEach(dish.links, id: \.self) { link in | |
| 28 | HStack(alignment: .firstTextBaseline) { | |
| 29 | Text(link.spacecraft).font(.footnote) | |
| 30 | Spacer() | |
| 31 | Text(describe(link, dish: dish)).font(.footnote.monospacedDigit()).dimmed(0.7) | |
| 32 | } | |
| 33 | .accessibilityElement(children: .combine) | |
| 34 | } | |
| 35 | } | |
| 36 | } | |
| 37 | .padding(.vertical, 4) | |
| 38 | } | |
| 39 | Text("Updated \(status.updated.formatted(date: .omitted, time: .shortened)). Data: NASA/JPL Deep Space Network.") | |
| 40 | .font(.caption2).dimmed(0.5) | |
| 41 | } else if failed { | |
| 42 | Text("Couldn't load Deep Space Network status.").font(.footnote).foregroundStyle(accent) | |
| 43 | } else { | |
| 44 | ProgressView().tint(ink) | |
| 45 | } | |
| 46 | } | |
| 47 | .task { | |
| 48 | while !Task.isCancelled { | |
| 49 | do { status = try await DSNStatus.fetch(); failed = false } catch { failed = status == nil } | |
| 50 | try? await Task.sleep(for: .seconds(30)) | |
| 51 | } | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | private func describe(_ l: DSNStatus.Link, dish: DSNStatus.Dish) -> String { | |
| 56 | var parts = [dish.name.replacingOccurrences(of: "DSS", with: "DSS ")] | |
| 57 | if l.receiving && l.sending { parts.append("two-way") } else if l.receiving { parts.append("receiving") } else { parts.append("sending") } | |
| 58 | if let r = l.downlinkRate { parts.append(rate(r)) } | |
| 59 | if let rt = l.roundTrip, rt > 60 { parts.append("round trip \(duration(rt))") } | |
| 60 | return parts.joined(separator: " · ") | |
| 61 | } | |
| 62 | ||
| 63 | private func rate(_ bps: Double) -> String { | |
| 64 | bps >= 1_000_000 ? String(format: "%.1f Mb/s", bps / 1_000_000) : bps >= 1000 ? String(format: "%.0f kb/s", bps / 1000) : String(format: "%.0f b/s", bps) | |
| 65 | } | |
| 66 | ||
| 67 | private func duration(_ s: Double) -> String { | |
| 68 | let h = Int(s / 3600), m = Int(s.truncatingRemainder(dividingBy: 3600) / 60) | |
| 69 | return h > 0 ? "\(h) h \(m) m" : "\(m) m" | |
| 70 | } | |
| 71 | } | |
App/Sources/SettingsScreen.swift +1
| @@ -143,6 +143,7 @@ struct CreditsScreen: View { | ||
| 143 | 143 | Credit(name: "Space weather and aurora forecast", detail: "NOAA Space Weather Prediction Center."), |
| 144 | 144 | Credit(name: "Images of the Sun", detail: "Courtesy of NASA/SDO and the AIA, EVE, and HMI science teams."), |
| 145 | 145 | Credit(name: "Launch schedule", detail: "The Space Devs, Launch Library 2."), |
| 146 | Credit(name: "Deep Space Network status", detail: "NASA/JPL, DSN Now."), | |
| 146 | 147 | ] |
| 147 | 148 | |
| 148 | 149 | /// Every distinct image credit used by the Library, grouped by licence. |
App/Sources/SystemScreen.swift +1
| @@ -87,6 +87,7 @@ struct SystemScreen: View { | ||
| 87 | 87 | } |
| 88 | 88 | } |
| 89 | 89 | } |
| 90 | DSNSection(ink: ink, accent: accent).padding(.top, 24) | |
| 90 | 91 | Text("Spacecraft positions: NASA/JPL Horizons. Pioneer 10 and 11 positions after contact was lost are predictions.") |
| 91 | 92 | .font(.caption2).dimmed(0.5).padding(.vertical, 16) |
| 92 | 93 | } |
Packages/MoonriseKit/Package.swift +1 −1
| @@ -26,7 +26,7 @@ let package = Package( | ||
| 26 | 26 | .target(name: "Feeds"), |
| 27 | 27 | .target(name: "Library", resources: [.copy("Resources/pages")]), |
| 28 | 28 | .testTarget(name: "SkyEngineTests", dependencies: ["SkyEngine"]), |
| 29 | .testTarget(name: "FeedsTests", dependencies: ["Feeds"]), | |
| 29 | .testTarget(name: "FeedsTests", dependencies: ["Feeds"], resources: [.copy("Fixtures")]), | |
| 30 | 30 | .testTarget(name: "LibraryTests", dependencies: ["Library", "SkyRenderer", "SkyEngine"]), |
| 31 | 31 | .testTarget(name: "SkyRendererTests", dependencies: ["SkyRenderer"]), |
| 32 | 32 | ] |
Packages/MoonriseKit/Sources/Feeds/DSN.swift added +95
| @@ -0,0 +1,95 @@ | ||
| 1 | import Foundation | |
| 2 | #if canImport(FoundationXML) | |
| 3 | import FoundationXML | |
| 4 | #endif | |
| 5 | ||
| 6 | /// NASA's Deep Space Network Now feed: what each antenna is talking to. | |
| 7 | public struct DSNStatus: Sendable { | |
| 8 | public struct Link: Sendable, Hashable { | |
| 9 | /// Display name, e.g. "Voyager 1". | |
| 10 | public var spacecraft: String | |
| 11 | public var receiving: Bool | |
| 12 | public var sending: Bool | |
| 13 | /// Bits per second of the active downlink, if any. | |
| 14 | public var downlinkRate: Double? | |
| 15 | /// Round-trip light time in seconds, if reported. | |
| 16 | public var roundTrip: Double? | |
| 17 | } | |
| 18 | ||
| 19 | public struct Dish: Sendable, Identifiable { | |
| 20 | public var name: String | |
| 21 | public var station: String | |
| 22 | public var activity: String | |
| 23 | public var links: [Link] | |
| 24 | public var id: String { name } | |
| 25 | } | |
| 26 | ||
| 27 | public var updated: Date | |
| 28 | public var dishes: [Dish] | |
| 29 | ||
| 30 | public static let url = URL(string: "https://eyes.nasa.gov/dsn/data/dsn.xml")! | |
| 31 | ||
| 32 | public static func fetch(session: URLSession = .shared) async throws -> DSNStatus { | |
| 33 | try decode(await session.data(from: url).0) | |
| 34 | } | |
| 35 | ||
| 36 | public static func decode(_ data: Data) throws -> DSNStatus { | |
| 37 | let p = Parser() | |
| 38 | let xml = XMLParser(data: data) | |
| 39 | xml.delegate = p | |
| 40 | guard xml.parse() else { throw xml.parserError ?? CocoaError(.coderReadCorrupt) } | |
| 41 | return DSNStatus(updated: p.updated, dishes: p.dishes) | |
| 42 | } | |
| 43 | ||
| 44 | public static func displayName(_ code: String) -> String { | |
| 45 | dsnSpacecraftNames[code.lowercased()] ?? code | |
| 46 | } | |
| 47 | ||
| 48 | final class Parser: NSObject, XMLParserDelegate { | |
| 49 | var updated = Date.distantPast | |
| 50 | var dishes: [Dish] = [] | |
| 51 | var station = "" | |
| 52 | var current: Dish? | |
| 53 | var signals: [String: (down: Bool, up: Bool, rate: Double?)] = [:] | |
| 54 | var rtlt: [String: Double] = [:] | |
| 55 | ||
| 56 | func parser(_ parser: XMLParser, didStartElement name: String, namespaceURI: String?, qualifiedName: String?, attributes a: [String: String]) { | |
| 57 | switch name { | |
| 58 | case "station": | |
| 59 | station = a["friendlyName"] ?? a["name"] ?? "" | |
| 60 | if let ms = a["timeUTC"].flatMap(Double.init) { updated = Date(timeIntervalSince1970: ms / 1000) } | |
| 61 | case "dish": | |
| 62 | current = Dish(name: a["name"] ?? "", station: station, activity: a["activity"] ?? "", links: []) | |
| 63 | signals = [:] | |
| 64 | rtlt = [:] | |
| 65 | case "downSignal", "upSignal": | |
| 66 | guard let sc = a["spacecraft"], !sc.isEmpty else { return } | |
| 67 | let active = a["active"] == "true" | |
| 68 | var s = signals[sc] ?? (false, false, nil) | |
| 69 | if name == "downSignal" { | |
| 70 | s.down = s.down || active | |
| 71 | if active, let r = a["dataRate"].flatMap(Double.init), r > 0 { s.rate = r } | |
| 72 | } else { | |
| 73 | s.up = s.up || active | |
| 74 | } | |
| 75 | signals[sc] = s | |
| 76 | case "target": | |
| 77 | if let n = a["name"], let t = a["rtlt"].flatMap(Double.init), t > 0 { rtlt[n] = t } | |
| 78 | default: | |
| 79 | break | |
| 80 | } | |
| 81 | } | |
| 82 | ||
| 83 | func parser(_ parser: XMLParser, didEndElement name: String, namespaceURI: String?, qualifiedName: String?) { | |
| 84 | guard name == "dish", var dish = current else { return } | |
| 85 | dish.links = signals | |
| 86 | .filter { $0.value.down || $0.value.up } | |
| 87 | .map { code, s in | |
| 88 | Link(spacecraft: DSNStatus.displayName(code), receiving: s.down, sending: s.up, downlinkRate: s.rate, roundTrip: rtlt[code]) | |
| 89 | } | |
| 90 | .sorted { $0.spacecraft < $1.spacecraft } | |
| 91 | dishes.append(dish) | |
| 92 | current = nil | |
| 93 | } | |
| 94 | } | |
| 95 | } | |
Packages/MoonriseKit/Sources/Feeds/DSNNames.swift added +173
| @@ -0,0 +1,173 @@ | ||
| 1 | /// Spacecraft display names from NASA's DSN Now configuration (eyes.nasa.gov/dsn/config.xml). | |
| 2 | let dsnSpacecraftNames: [String: String] = [ | |
| 3 | "ace": "Advanced Composition Explorer", | |
| 4 | "agm1": "Astrobotic Griffin Lander", | |
| 5 | "apm1": "Astrobotic Peregrine 1 Mission", | |
| 6 | "argo": "ArgoMoon", | |
| 7 | "atot": "Advanced Tracking and Observational Techniques", | |
| 8 | "bepi": "BepiColombo", | |
| 9 | "bios": "BioSentinel", | |
| 10 | "caps": "CAPSTONE", | |
| 11 | "cas": "Cassini", | |
| 12 | "cass": "Testing", | |
| 13 | "cgo": "Carruthers Geocorona Observatory", | |
| 14 | "ch1": "Chandrayaan", | |
| 15 | "ch2": "Chandrayaan-2", | |
| 16 | "ch2l": "Chandrayaan-2 Lander", | |
| 17 | "ch2o": "Chandrayaan-2 Orbiter", | |
| 18 | "ch3": "Chandrayaan-3", | |
| 19 | "chdr": "Chandra", | |
| 20 | "clu1": "Cluster 1", | |
| 21 | "clu2": "Cluster 2", | |
| 22 | "clu3": "Cluster 3", | |
| 23 | "clu4": "Cluster 4", | |
| 24 | "cue3": "CU Earth Escape Explorer", | |
| 25 | "cusp": "CubeSat for Solar Particles", | |
| 26 | "dart": "Double Asteroid Redirection Test", | |
| 27 | "dawn": "Dawn", | |
| 28 | "dif": "Deep Impact", | |
| 29 | "dsco": "Deep Space Climate Observatory (DSCOVR)", | |
| 30 | "dsn": "Testing", | |
| 31 | "egs": "EVN and Global Services", | |
| 32 | "em-1": "Exploration Mission-1", | |
| 33 | "em-10": "Exploration Mission-10", | |
| 34 | "em-2": "Exploration Mission-2", | |
| 35 | "em-3": "Exploration Mission-3", | |
| 36 | "em-4": "Exploration Mission-4", | |
| 37 | "em-5": "Exploration Mission-5", | |
| 38 | "em-6": "Exploration Mission-6", | |
| 39 | "em-7": "Exploration Mission-7", | |
| 40 | "em-8": "Exploration Mission-8", | |
| 41 | "em-9": "Exploration Mission-9", | |
| 42 | "em1": "Human Space Flight: Artemis I", | |
| 43 | "em2": "Human Space Flight: Artemis II", | |
| 44 | "em3": "Human Space Flight: Artemis III", | |
| 45 | "emm": "Emirates Mars Mission (Hope)", | |
| 46 | "equl": "EQUULEUS", | |
| 47 | "escb": "ESCAPADE Blue", | |
| 48 | "escg": "ESCAPADE Gold", | |
| 49 | "eurc": "Europa Clipper", | |
| 50 | "eus": "Exploration Upper Stage", | |
| 51 | "gaia": "Gaia", | |
| 52 | "gbra": "Ground Based Radio Astronomy", | |
| 53 | "go10": "GOES 10", | |
| 54 | "go11": "GOES 11", | |
| 55 | "go12": "GOES 12", | |
| 56 | "go13": "GOES 13", | |
| 57 | "go14": "GOES 14", | |
| 58 | "go15": "GOES 15", | |
| 59 | "go16": "GOES 16", | |
| 60 | "go17": "GOES 17", | |
| 61 | "grla": "GRAIL A", | |
| 62 | "grlb": "GRAIL B", | |
| 63 | "gssr": "Goldstone Solar System Radar", | |
| 64 | "gtl": "Geotail", | |
| 65 | "gvrt": "Goldstone Apple Valley Radio Telescope", | |
| 66 | "hcra": "Host Country Radio Astronomy", | |
| 67 | "hmap": "LunaH-Map", | |
| 68 | "hst": "Hubble Space Telescope", | |
| 69 | "hyb2": "Hayabusa-2", | |
| 70 | "ice": "ISEE-3 Reboot", | |
| 71 | "icps": "Interim Cryogenic Propulsion Stage", | |
| 72 | "imag": "IMAGE", | |
| 73 | "imap": "IMAP", | |
| 74 | "intg": "INTEGRAL", | |
| 75 | "jno": "Juno", | |
| 76 | "jnsa": "Janus A", | |
| 77 | "jnsb": "Janus B", | |
| 78 | "jwst": "James Webb Space Telescope", | |
| 79 | "kepl": "Kepler", | |
| 80 | "kplo": "Korea Pathfinder Lunar Orbiter", | |
| 81 | "lade": "LADEE", | |
| 82 | "lcro": "LCROSS", | |
| 83 | "lfl": "Lunar Flashlight", | |
| 84 | "lici": "LICIACube", | |
| 85 | "lnd1": "Lunar Node 1", | |
| 86 | "lro": "Lunar Reconnaissance Orbiter", | |
| 87 | "ltb": "Lunar Trailblazer", | |
| 88 | "ltst": "Interim Cryogenic Propulsion Stage", | |
| 89 | "lucy": "Lucy", | |
| 90 | "lunah-map": "Lunar Hydrogen MAPper", | |
| 91 | "m01o": "Mars Odyssey", | |
| 92 | "m01s": "Mars Odyssey", | |
| 93 | "m20": "Mars 2020 (Perseverance)", | |
| 94 | "map": "WMAP", | |
| 95 | "mcoa": "MarCO A", | |
| 96 | "mcob": "MarCO B", | |
| 97 | "mer1": "Opportunity", | |
| 98 | "mer2": "Spirit", | |
| 99 | "mex": "Mars Express", | |
| 100 | "mgs": "Mars Global Surveyor", | |
| 101 | "mlic": "Lunar IceCube", | |
| 102 | "mms1": "MMS 1", | |
| 103 | "mms2": "MMS 2", | |
| 104 | "mms3": "MMS 3", | |
| 105 | "mms4": "MMS 4", | |
| 106 | "mmx": "MMX", | |
| 107 | "mom": "Mars Orbiter Mission", | |
| 108 | "mro": "Mars Reconnaissance Orbiter", | |
| 109 | "mros": "Mars Reconnaissance Orbiter", | |
| 110 | "msgr": "MESSENGER", | |
| 111 | "msl": "Mars Science Laboratory (Curiosity)", | |
| 112 | "musc": "Hayabusa", | |
| 113 | "mvn": "MAVEN", | |
| 114 | "neas": "Near Earth Asteroid Scout", | |
| 115 | "nhpc": "New Horizons", | |
| 116 | "no15": "NOAA 15", | |
| 117 | "no16": "NOAA 16", | |
| 118 | "no17": "NOAA 17", | |
| 119 | "no18": "NOAA 18", | |
| 120 | "nsyt": "InSight", | |
| 121 | "olin": "SWARM-EX", | |
| 122 | "omot": "OMOTENASHI", | |
| 123 | "orx": "OSIRIS-REx", | |
| 124 | "phx": "Phoenix", | |
| 125 | "plc": "Akatsuki", | |
| 126 | "polr": "POLAR", | |
| 127 | "psyc": "Psyche", | |
| 128 | "rd1": "Red Dragon 1", | |
| 129 | "rfc": "Reference Frame Calibration", | |
| 130 | "rose": "Rosetta", | |
| 131 | "rp": "Resource Prospector", | |
| 132 | "rsp": "ExoMars Rover and Surface Platform", | |
| 133 | "rst": "Roman Space Telescope", | |
| 134 | "rsts": "Resource System Time Sharing", | |
| 135 | "sdu": "Stardust", | |
| 136 | "sele": "Kaguya", | |
| 137 | "sgp": "Space Geodesy Program", | |
| 138 | "slim": "Smart Lander for Investigating Moon", | |
| 139 | "soho": "SOHO", | |
| 140 | "spil": "Beresheet", | |
| 141 | "spp": "Parker Solar Probe", | |
| 142 | "sta": "STEREO A", | |
| 143 | "stab": "STEREO B", | |
| 144 | "stb": "STEREO B", | |
| 145 | "stf": "Spitzer Space Telescope", | |
| 146 | "swfo": "Space Weather Follow On-Lagrange 1", | |
| 147 | "td10": "TDRS 10", | |
| 148 | "td11": "TDRS 11", | |
| 149 | "td12": "TDRS 12", | |
| 150 | "td13": "TDRS 13", | |
| 151 | "tdr1": "TDRS 1", | |
| 152 | "tdr3": "TDRS 3", | |
| 153 | "tdr4": "TDRS 4", | |
| 154 | "tdr5": "TDRS 5", | |
| 155 | "tdr6": "TDRS 6", | |
| 156 | "tdr7": "TDRS 7", | |
| 157 | "tdr8": "TDRS 8", | |
| 158 | "tdr9": "TDRS 9", | |
| 159 | "terr": "TERRA", | |
| 160 | "tess": "Transiting Exoplanet Survey Satellite", | |
| 161 | "tgo": "Trace Gas Orbiter", | |
| 162 | "thb": "THEMIS B", | |
| 163 | "thc": "THEMIS C", | |
| 164 | "tm": "Team Miles", | |
| 165 | "tmm": "Team Miles", | |
| 166 | "ulys": "Ulysses", | |
| 167 | "vex": "Venus Express", | |
| 168 | "vgr1": "Voyager 1", | |
| 169 | "vgr2": "Voyager 2", | |
| 170 | "vlbi": "V.L.B. Interferometry", | |
| 171 | "wind": "WIND", | |
| 172 | "xmm": "X-ray Multi-Mirror Mission (XMM-Newton)", | |
| 173 | ] | |
Packages/MoonriseKit/Tests/FeedsTests/DSNTests.swift added +32
| @@ -0,0 +1,32 @@ | ||
| 1 | import Foundation | |
| 2 | import Testing | |
| 3 | @testable import Feeds | |
| 4 | ||
| 5 | @Test func decodesLiveDSNSnapshot() throws { | |
| 6 | // dsn.xml saved from eyes.nasa.gov/dsn/data/dsn.xml on 2026-10-18. | |
| 7 | let url = try #require(Bundle.module.url(forResource: "Fixtures/dsn", withExtension: "xml")) | |
| 8 | let s = try DSNStatus.decode(Data(contentsOf: url)) | |
| 9 | #expect(s.dishes.count == 15) | |
| 10 | #expect(Set(s.dishes.map(\.station)) == ["Goldstone", "Madrid", "Canberra"]) | |
| 11 | #expect(s.updated > Date(timeIntervalSince1970: 1_790_000_000)) | |
| 12 | #expect(s.dishes.first { $0.name == "DSS14" }?.activity == "Engineering Upgrades") | |
| 13 | } | |
| 14 | ||
| 15 | @Test func linksNeedAnActiveSignal() throws { | |
| 16 | let xml = Data(""" | |
| 17 | <dsn><station name="gdscc" friendlyName="Goldstone" timeUTC="1792312582000"/> | |
| 18 | <dish name="DSS43" activity="Spacecraft Telemetry"> | |
| 19 | <downSignal active="true" dataRate="160" band="X" spacecraft="VGR2" spacecraftID="-32"/> | |
| 20 | <upSignal active="false" spacecraft="VGR2" spacecraftID="-32"/> | |
| 21 | <downSignal active="false" spacecraft="MRO" spacecraftID="-74"/> | |
| 22 | <target name="VGR2" id="32" rtlt="138000"/> | |
| 23 | </dish></dsn> | |
| 24 | """.utf8) | |
| 25 | let s = try DSNStatus.decode(xml) | |
| 26 | let links = try #require(s.dishes.first?.links) | |
| 27 | #expect(links.count == 1) | |
| 28 | #expect(links[0].spacecraft == "Voyager 2") | |
| 29 | #expect(links[0].receiving && !links[0].sending) | |
| 30 | #expect(links[0].downlinkRate == 160) | |
| 31 | #expect(links[0].roundTrip == 138000) | |
| 32 | } | |
Packages/MoonriseKit/Tests/FeedsTests/Fixtures/dsn.xml added +74
| @@ -0,0 +1,74 @@ | ||
| 1 | <dsn> | |
| 2 | <station name="gdscc" friendlyName="Goldstone" timeUTC="1792312582000" timeZoneOffset="-25200000.0"/> | |
| 3 | <dish name="DSS25" azimuthAngle="97" elevationAngle="41" windSpeed="2" isMSPA="false" isArray="false" isDDOR="false" activity="DSN Very Long Baseline Interferometry"> | |
| 4 | <target name="DSN" id="99" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 5 | </dish> | |
| 6 | <dish name="DSS14" azimuthAngle="0" elevationAngle="90" windSpeed="" isMSPA="false" isArray="false" isDDOR="false" activity="Engineering Upgrades"> | |
| 7 | <target name="DSN" id="99" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 8 | </dish> | |
| 9 | <dish name="DSS24" azimuthAngle="72" elevationAngle="7" windSpeed="2" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 10 | <downSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="-140" spacecraft="MRO" spacecraftID="-74"/> | |
| 11 | <upSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="0" spacecraft="MRO" spacecraftID="-74"/> | |
| 12 | <downSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="-150" spacecraft="TGO" spacecraftID="-143"/> | |
| 13 | <target name="MRO" id="74" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 14 | <target name="TGO" id="143" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 15 | </dish> | |
| 16 | <dish name="DSS23" azimuthAngle="72" elevationAngle="7" windSpeed="0" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 17 | <upSignal active="false" signalType="none" dataRate="0" frequency="0" band="S" power="0" spacecraft="M01O" spacecraftID="-53"/> | |
| 18 | <downSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="-480" spacecraft="M01O" spacecraftID="-53"/> | |
| 19 | <target name="M01O" id="53" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 20 | </dish> | |
| 21 | <dish name="DSS26" azimuthAngle="249" elevationAngle="34" windSpeed="2" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 22 | <upSignal active="true" signalType="data" dataRate="0" frequency="0" band="S" power="0.2" spacecraft="MMS1" spacecraftID="-108"/> | |
| 23 | <downSignal active="true" signalType="data" dataRate="0" frequency="0" band="S" power="-110" spacecraft="MMS1" spacecraftID="-108"/> | |
| 24 | <target name="MMS1" id="108" uplegRange="146000" downlegRange="146000" rtlt="-1"/> | |
| 25 | </dish> | |
| 26 | <station name="mdscc" friendlyName="Madrid" timeUTC="1792312582000" timeZoneOffset="7200000.0"/> | |
| 27 | <dish name="DSS55" azimuthAngle="0" elevationAngle="90" windSpeed="" isMSPA="false" isArray="false" isDDOR="false" activity="Engineering Upgrades"> | |
| 28 | <target name="DSN" id="99" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 29 | </dish> | |
| 30 | <dish name="DSS63" azimuthAngle="0" elevationAngle="90" windSpeed="" isMSPA="false" isArray="false" isDDOR="false" activity="Engineering Upgrades"> | |
| 31 | <target name="DSN" id="99" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 32 | </dish> | |
| 33 | <dish name="DSS54" azimuthAngle="302" elevationAngle="27" windSpeed="6" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 34 | <upSignal active="true" signalType="data" dataRate="0" frequency="0" band="S" power="2" spacecraft="TESS" spacecraftID="-95"/> | |
| 35 | <downSignal active="false" signalType="none" dataRate="115400000" frequency="0" band="K" power="-400" spacecraft="TESS" spacecraftID="-95"/> | |
| 36 | <downSignal active="true" signalType="data" dataRate="1000000" frequency="0" band="S" power="-110" spacecraft="TESS" spacecraftID="-95"/> | |
| 37 | <target name="TESS" id="95" uplegRange="113000" downlegRange="113000" rtlt="-1"/> | |
| 38 | </dish> | |
| 39 | <dish name="DSS53" azimuthAngle="195" elevationAngle="63" windSpeed="6" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 40 | <upSignal active="true" signalType="data" dataRate="0" frequency="0" band="X" power="18" spacecraft="JNO" spacecraftID="-61"/> | |
| 41 | <downSignal active="true" signalType="data" dataRate="25980" frequency="0" band="X" power="-130" spacecraft="JNO" spacecraftID="-61"/> | |
| 42 | <target name="JNO" id="61" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 43 | </dish> | |
| 44 | <dish name="DSS56" azimuthAngle="139" elevationAngle="42" windSpeed="6" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 45 | <upSignal active="true" signalType="data" dataRate="0" frequency="0" band="S" power="0.1" spacecraft="SOHO" spacecraftID="-21"/> | |
| 46 | <downSignal active="true" signalType="data" dataRate="245800" frequency="0" band="S" power="-110" spacecraft="SOHO" spacecraftID="-21"/> | |
| 47 | <target name="SOHO" id="21" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 48 | </dish> | |
| 49 | <dish name="DSS65" azimuthAngle="80" elevationAngle="90" windSpeed="6" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 50 | <upSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="0" spacecraft="STA" spacecraftID="-234"/> | |
| 51 | <downSignal active="false" signalType="none" dataRate="0" frequency="0" band="X" power="-470" spacecraft="STA" spacecraftID="-234"/> | |
| 52 | <target name="STA" id="234" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 53 | </dish> | |
| 54 | <station name="cdscc" friendlyName="Canberra" timeUTC="1792312582000" timeZoneOffset="39600000.0"/> | |
| 55 | <dish name="DSS34" azimuthAngle="0" elevationAngle="90" windSpeed="" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 56 | <downSignal active="true" signalType="data" dataRate="160" frequency="0" band="X" power="-160" spacecraft="VGR2" spacecraftID="-32"/> | |
| 57 | <downSignal active="true" signalType="data" dataRate="0" frequency="0" band="X" power="-170" spacecraft="VGR2" spacecraftID="-32"/> | |
| 58 | <target name="VGR2" id="32" uplegRange="21600000000" downlegRange="21600000000" rtlt="-1"/> | |
| 59 | </dish> | |
| 60 | <dish name="DSS35" azimuthAngle="182" elevationAngle="66" windSpeed="0" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 61 | <downSignal active="true" signalType="data" dataRate="0" frequency="0" band="X" power="-170" spacecraft="VGR2" spacecraftID="-32"/> | |
| 62 | <target name="VGR2" id="32" uplegRange="21600000000" downlegRange="21600000000" rtlt="-1"/> | |
| 63 | </dish> | |
| 64 | <dish name="DSS43" azimuthAngle="261" elevationAngle="56" windSpeed="0" isMSPA="false" isArray="false" isDDOR="false" activity="Science Radar Astronomy"> | |
| 65 | <target name="GBRA" id="99" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 66 | </dish> | |
| 67 | <dish name="DSS36" azimuthAngle="316" elevationAngle="75" windSpeed="0" isMSPA="false" isArray="false" isDDOR="false" activity="Spacecraft Telemetry, Tracking, and Command"> | |
| 68 | <upSignal active="true" signalType="data" dataRate="0" frequency="0" band="S" power="0.1" spacecraft="LRO" spacecraftID="-85"/> | |
| 69 | <downSignal active="true" signalType="data" dataRate="146400" frequency="0" band="S" power="-110" spacecraft="LRO" spacecraftID="-85"/> | |
| 70 | <downSignal active="true" signalType="data" dataRate="28590000" frequency="0" band="K" power="-90" spacecraft="LRO" spacecraftID="-85"/> | |
| 71 | <target name="LRO" id="85" uplegRange="-1" downlegRange="-1" rtlt="-1"/> | |
| 72 | </dish> | |
| 73 | <timestamp>1792312582000</timestamp> | |
| 74 | </dsn> | |