Write LOCATION to Cabrillo, and give CQ WW M/2 eight band changes an hour

CQ WW lists LOCATION as required, and the export never wrote it. It now
carries the ARRL section, state or province, or DX.

CQ WW M/2 has no stay on a band: it may make eight band changes in a clock
hour. It was getting the ten-minute stay that M/S has.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 14:18:42 +00:00
co-authored by Claude Sonnet 5.5
parent b5043506ae
commit 0ad894bfae
6 changed files with 44 additions and 0 deletions
@@ -122,6 +122,7 @@ public sealed partial class EntryWindow
TransmitterCategory = Logging.Instance.TransmitterCategory, TransmitterCategory = Logging.Instance.TransmitterCategory,
OverlayCategory = Logging.Instance.OverlayCategory, OverlayCategory = Logging.Instance.OverlayCategory,
TimeCategory = Logging.Instance.TimeCategory, TimeCategory = Logging.Instance.TimeCategory,
Location = CabrilloLocation(Logging.Me),
ClaimedScore = Logging.Log.TotalScore, ClaimedScore = Logging.Log.TotalScore,
Club = Logging.Me.Club, Club = Logging.Me.Club,
Name = Logging.Me.Name, Name = Logging.Me.Name,
@@ -132,6 +133,20 @@ public sealed partial class EntryWindow
Status($"{Logging.Log.Qsos.Count} contacts written to {Path.GetFileName(path)}"); Status($"{Logging.Log.Qsos.Count} contacts written to {Path.GetFileName(path)}");
} }
/// The section, state or province for a station in the US or Canada, and
/// `DX` for any other station.
private static string CabrilloLocation(StationInfo me)
{
foreach (string place in new[] { me.ArrlSection, me.State, me.Province })
{
if (place.Trim().Length > 0)
{
return place.Trim().ToUpperInvariant();
}
}
return "DX";
}
/// The contacts alone, which is the file to hand to another program. ADIF /// The contacts alone, which is the file to hand to another program. ADIF
/// has no QTC record, and N1MM leaves the traffic out for that reason. /// has no QTC record, and N1MM leaves the traffic out for that reason.
private void OnExportAdif(object? sender, RoutedEventArgs e) => private void OnExportAdif(object? sender, RoutedEventArgs e) =>
+7
View File
@@ -67,6 +67,13 @@ public sealed class CqWorldWide : Contest
public bool HasSerialNumbers => false; public bool HasSerialNumbers => false;
/// Multi-single stays ten minutes on a band, which is the category default.
/// Multi-two has no stay: it may make eight band changes in a clock hour.
public BandChangeRules BandChangesFor(ContestEntry entry) =>
EntryCategories.IsMultiTwo(entry)
? new BandChangeRules(8)
: BandChangeRules.ForCategory(entry);
public IReadOnlyList<ModeCategory> Modes => [mode]; public IReadOnlyList<ModeCategory> Modes => [mode];
/// The report is fixed for the whole contest, so the sent exchange is the /// The report is fixed for the whole contest, so the sent exchange is the
@@ -27,6 +27,10 @@ public sealed record CabrilloHeader
public string TimeCategory { get; init; } = ""; public string TimeCategory { get; init; } = "";
/// The state, province or ARRL section of a station in the US or Canada,
/// and `DX` for everywhere else, which is what CQ WW asks for.
public string Location { get; init; } = "";
public long ClaimedScore { get; init; } public long ClaimedScore { get; init; }
public string Club { get; init; } = ""; public string Club { get; init; } = "";
@@ -35,6 +35,7 @@ public sealed class CabrilloWriter
Line(text, "CATEGORY-TRANSMITTER", header.TransmitterCategory); Line(text, "CATEGORY-TRANSMITTER", header.TransmitterCategory);
Line(text, "CATEGORY-OVERLAY", header.OverlayCategory); Line(text, "CATEGORY-OVERLAY", header.OverlayCategory);
Line(text, "CATEGORY-TIME", header.TimeCategory); Line(text, "CATEGORY-TIME", header.TimeCategory);
Line(text, "LOCATION", header.Location);
text.Append(CultureInfo.InvariantCulture, $"CLAIMED-SCORE: {header.ClaimedScore}\r\n"); text.Append(CultureInfo.InvariantCulture, $"CLAIMED-SCORE: {header.ClaimedScore}\r\n");
Line(text, "CLUB", header.Club); Line(text, "CLUB", header.Club);
Line(text, "NAME", header.Name); Line(text, "NAME", header.Name);
@@ -56,6 +56,21 @@ public class BandChangeRulesTests
Assert.Equal(TimeSpan.FromMinutes(10), rules.MinimumStay); Assert.Equal(TimeSpan.FromMinutes(10), rules.MinimumStay);
} }
[Fact]
public void CqWwMultiTwoMayMakeEightBandChangesAnHourAndHasNoStay()
{
Contest contest = new Rules.CqWorldWide(ModeCategory.Phone);
BandChangeRules rules = contest.BandChangesFor(new ContestEntry
{
OperatorCategory = "MULTI-OP",
TransmitterCategory = "TWO",
});
Assert.Equal(8, rules.Max);
Assert.False(rules.HasStayTimer);
}
[Fact] [Fact]
public void ASingleOperatorEntryHasNoBandChangeRule() public void ASingleOperatorEntryHasNoBandChangeRule()
{ {
@@ -70,6 +70,8 @@ public class CabrilloWriterTests
Assert.StartsWith("START-OF-LOG: 3.0\r\n", log); Assert.StartsWith("START-OF-LOG: 3.0\r\n", log);
Assert.Contains("CONTEST: CQ-WW-CW\r\n", log); Assert.Contains("CONTEST: CQ-WW-CW\r\n", log);
Assert.Contains("CLAIMED-SCORE: 1234\r\n", log); Assert.Contains("CLAIMED-SCORE: 1234\r\n", log);
Assert.Contains("LOCATION: DX\r\n", writer.Write(
new CabrilloHeader { Contest = "CQ-WW-CW", Callsign = "DL1ABC", Location = "DX" }, []));
Assert.EndsWith("END-OF-LOG:\r\n", log); Assert.EndsWith("END-OF-LOG:\r\n", log);
} }