Make Radio dataclass store list of ranges

This commit is contained in:
Kangwook Lee 2021-08-04 23:44:48 +09:00 committed by Dan Albert
parent 8608b73009
commit c58ecd96f0

View File

@ -2,7 +2,7 @@
import itertools
import logging
from dataclasses import dataclass
from typing import Dict, Iterator, List, Set
from typing import Dict, FrozenSet, Iterator, List, Reversible, Set, Tuple
@dataclass(frozen=True)
@ -45,14 +45,8 @@ def kHz(num: int) -> RadioFrequency:
@dataclass(frozen=True)
class Radio:
"""A radio.
Defines the minimum (inclusive) and maximum (exclusive) range of the radio.
"""
#: The name of the radio.
name: str
class RadioRange:
"""Defines the minimum (inclusive) and maximum (exclusive) range of the radio."""
#: The minimum (inclusive) frequency tunable by this radio.
minimum: RadioFrequency
@ -63,19 +57,51 @@ class Radio:
#: The spacing between adjacent frequencies.
step: RadioFrequency
def __str__(self) -> str:
return self.name
#: Specific frequencies to exclude. (e.g. Guard channels)
excludes: FrozenSet[RadioFrequency] = frozenset()
def range(self) -> Iterator[RadioFrequency]:
"""Returns an iterator over the usable frequencies of this radio."""
return (
RadioFrequency(x)
for x in range(self.minimum.hertz, self.maximum.hertz, self.step.hertz)
if RadioFrequency(x) not in self.excludes
)
@property
def last_channel(self) -> RadioFrequency:
return RadioFrequency(self.maximum.hertz - self.step.hertz)
return next(
RadioFrequency(x)
for x in reversed(
range(self.minimum.hertz, self.maximum.hertz, self.step.hertz)
)
if RadioFrequency(x) not in self.excludes
)
@dataclass(frozen=True)
class Radio:
"""A radio.
Defines ranges of usable frequencies of the radio.
"""
#: The name of the radio.
name: str
#: List of usable frequency range of this radio.
ranges: Tuple[RadioRange, ...]
def __str__(self) -> str:
return self.name
def range(self) -> Iterator[RadioFrequency]:
"""Returns an iterator over the usable frequencies of this radio."""
return itertools.chain.from_iterable(rng.range() for rng in self.ranges)
@property
def last_channel(self) -> RadioFrequency:
return self.ranges[-1].last_channel
class ChannelInUseError(RuntimeError):
@ -88,53 +114,53 @@ class ChannelInUseError(RuntimeError):
# TODO: Figure out appropriate steps for each radio. These are just guesses.
#: List of all known radios used by aircraft in the game.
RADIOS: List[Radio] = [
Radio("AN/ARC-164", MHz(225), MHz(400), step=MHz(1)),
Radio("AN/ARC-186(V) AM", MHz(116), MHz(152), step=MHz(1)),
Radio("AN/ARC-186(V) FM", MHz(30), MHz(76), step=MHz(1)),
Radio("AN/ARC-164", (RadioRange(MHz(225), MHz(400), step=MHz(1)),)),
Radio("AN/ARC-186(V) AM", (RadioRange(MHz(116), MHz(152), step=MHz(1)),)),
Radio("AN/ARC-186(V) FM", (RadioRange(MHz(30), MHz(76), step=MHz(1)),)),
# The AN/ARC-210 can also use [30, 88) and [108, 118), but the current
# implementation can't implement the gap and the radio can't transmit on the
# latter. There's still plenty of channels between 118 MHz and 400 MHz, so
# not worth worrying about.
Radio("AN/ARC-210", MHz(118), MHz(400), step=MHz(1)),
Radio("AN/ARC-222", MHz(116), MHz(174), step=MHz(1)),
Radio("SCR-522", MHz(100), MHz(156), step=MHz(1)),
Radio("A.R.I. 1063", MHz(100), MHz(156), step=MHz(1)),
Radio("BC-1206", kHz(200), kHz(400), step=kHz(10)),
Radio("AN/ARC-210", (RadioRange(MHz(118), MHz(400), step=MHz(1)),)),
Radio("AN/ARC-222", (RadioRange(MHz(116), MHz(174), step=MHz(1)),)),
Radio("SCR-522", (RadioRange(MHz(100), MHz(156), step=MHz(1)),)),
Radio("A.R.I. 1063", (RadioRange(MHz(100), MHz(156), step=MHz(1)),)),
Radio("BC-1206", (RadioRange(kHz(200), kHz(400), step=kHz(10)),)),
# Note: The M2000C V/UHF can operate in both ranges, but has a gap between
# 150 MHz and 225 MHz. We can't allocate in that gap, and the current
# system doesn't model gaps, so just pretend it ends at 150 MHz for now. We
# can model gaps later if needed.
Radio("TRT ERA 7000 V/UHF", MHz(118), MHz(150), step=MHz(1)),
Radio("TRT ERA 7200 UHF", MHz(225), MHz(400), step=MHz(1)),
Radio("TRT ERA 7000 V/UHF", (RadioRange(MHz(118), MHz(150), step=MHz(1)),)),
Radio("TRT ERA 7200 UHF", (RadioRange(MHz(225), MHz(400), step=MHz(1)),)),
# Tomcat radios
# # https://www.heatblur.se/F-14Manual/general.html#an-arc-159-uhf-1-radio
Radio("AN/ARC-159", MHz(225), MHz(400), step=MHz(1)),
Radio("AN/ARC-159", (RadioRange(MHz(225), MHz(400), step=MHz(1)),)),
# AN/ARC-182 can also operate from 30 MHz to 88 MHz, as well as from 225 MHz
# to 400 MHz range, but we can't model gaps with the current implementation.
# https://www.heatblur.se/F-14Manual/general.html#an-arc-182-v-uhf-2-radio
Radio("AN/ARC-182", MHz(108), MHz(174), step=MHz(1)),
Radio("AN/ARC-182", (RadioRange(MHz(108), MHz(174), step=MHz(1)),)),
# Also capable of [103, 156) at 25 kHz intervals, but we can't do gaps.
Radio("FR 22", MHz(225), MHz(400), step=kHz(50)),
Radio("FR 22", (RadioRange(MHz(225), MHz(400), step=kHz(50)),)),
# P-51 / P-47 Radio
# 4 preset channels (A/B/C/D)
Radio("SCR522", MHz(100), MHz(156), step=kHz(25)),
Radio("R&S M3AR VHF", MHz(120), MHz(174), step=MHz(1)),
Radio("R&S M3AR UHF", MHz(225), MHz(400), step=MHz(1)),
Radio("SCR522", (RadioRange(MHz(100), MHz(156), step=kHz(25)),)),
Radio("R&S M3AR VHF", (RadioRange(MHz(120), MHz(174), step=MHz(1)),)),
Radio("R&S M3AR UHF", (RadioRange(MHz(225), MHz(400), step=MHz(1)),)),
# MiG-15bis
Radio("RSI-6K HF", MHz(3, 750), MHz(5), step=kHz(25)),
Radio("RSI-6K HF", (RadioRange(MHz(3, 750), MHz(5), step=kHz(25)),)),
# MiG-19P
Radio("RSIU-4V", MHz(100), MHz(150), step=MHz(1)),
Radio("RSIU-4V", (RadioRange(MHz(100), MHz(150), step=MHz(1)),)),
# MiG-21bis
Radio("RSIU-5V", MHz(118), MHz(140), step=MHz(1)),
Radio("RSIU-5V", (RadioRange(MHz(118), MHz(140), step=MHz(1)),)),
# Ka-50
# Note: Also capable of 100MHz-150MHz, but we can't model gaps.
Radio("R-800L1", MHz(220), MHz(400), step=kHz(25)),
Radio("R-828", MHz(20), MHz(60), step=kHz(25)),
Radio("R-800L1", (RadioRange(MHz(220), MHz(400), step=kHz(25)),)),
Radio("R-828", (RadioRange(MHz(20), MHz(60), step=kHz(25)),)),
# UH-1H
Radio("AN/ARC-51BX", MHz(225), MHz(400), step=kHz(50)),
Radio("AN/ARC-131", MHz(30), MHz(76), step=kHz(50)),
Radio("AN/ARC-134", MHz(116), MHz(150), step=kHz(25)),
Radio("R&S Series 6000", MHz(100), MHz(156), step=kHz(25)),
Radio("AN/ARC-51BX", (RadioRange(MHz(225), MHz(400), step=kHz(50)),)),
Radio("AN/ARC-131", (RadioRange(MHz(30), MHz(76), step=kHz(50)),)),
Radio("AN/ARC-134", (RadioRange(MHz(116), MHz(150), step=kHz(25)),)),
Radio("R&S Series 6000", (RadioRange(MHz(100), MHz(156), step=kHz(25)),)),
]
@ -175,7 +201,7 @@ class RadioRegistry:
# Not a real radio, but useful for allocating a channel usable for
# inter-flight communications.
BLUFOR_UHF = Radio("BLUFOR UHF", MHz(225), MHz(400), step=MHz(1))
BLUFOR_UHF = Radio("BLUFOR UHF", (RadioRange(MHz(225), MHz(400), step=MHz(1)),))
def __init__(self) -> None:
self.allocated_channels: Set[RadioFrequency] = set()