-
-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathYaesuFt991CatCodec.cs
More file actions
127 lines (102 loc) · 3.88 KB
/
Copy pathYaesuFt991CatCodec.cs
File metadata and controls
127 lines (102 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
namespace OscarWatch.Core.Radio;
/// <summary>
/// Yaesu FT-991 / FT-991A / FTX-1 ASCII CAT (newcat / Hamlib-compatible subset).
/// Frequencies are 9-digit Hz on VFO-A (FA) / VFO-B (FB).
/// </summary>
public static class YaesuFt991CatCodec
{
public const int FrequencyDigits = 9;
public const long MinFrequencyHz = 30_000;
public const long MaxFrequencyHz = 470_000_000;
/// <summary>CTCSS tone table (Hamlib common_ctcss_list / FT-991 manual Table 1).</summary>
public static readonly double[] CtcssTonesHz =
[
67.0, 69.3, 71.9, 74.4, 77.0, 79.7, 82.5, 85.4, 88.5, 91.5,
94.8, 97.4, 100.0, 103.5, 107.2, 110.9, 114.8, 118.8, 123.0, 127.3,
131.8, 136.5, 141.3, 146.2, 151.4, 156.7, 162.2, 167.9, 173.8, 179.9,
186.2, 192.8, 203.5, 210.7, 218.1, 225.7, 233.6, 241.8, 250.3, 254.1
];
public static string BuildReadFrequencyCommand(bool vfoB) =>
vfoB ? "FB;" : "FA;";
public static string BuildSetFrequencyCommand(bool vfoB, long hz)
{
if (hz < MinFrequencyHz || hz > MaxFrequencyHz)
throw new ArgumentOutOfRangeException(nameof(hz));
return vfoB ? $"FB{hz:D9};" : $"FA{hz:D9};";
}
/// <summary>P1=0 MAIN RX on VFO-A.</summary>
public static string BuildSetModeCommand(char modeCode) => $"MD0{modeCode};";
/// <summary>FT P1=2 TX on VFO-A, P1=3 TX on VFO-B (split).</summary>
public static string BuildSetTxVfoCommand(bool txOnVfoB) => txOnVfoB ? "FT3;" : "FT2;";
/// <summary>Copy VFO-A frequency and mode to VFO-B.</summary>
public static string BuildCopyVfoAToBCommand() => "AB;";
public static string BuildDialLockCommand(bool on) => on ? "LK1;" : "LK0;";
public static string BuildCtcssOffCommand() => "CT00;";
public static string BuildCtcssEncodeCommand(int zeroBasedIndex) =>
$"CN00{zeroBasedIndex:D3};CT02;";
public static string BuildCtcssSquelchCommand(int zeroBasedIndex) =>
$"CN0{zeroBasedIndex:D3};CT01;";
public static bool TryParseFrequencyHz(ReadOnlySpan<char> response, out long hz)
{
hz = 0;
if (response.Length < 2 + FrequencyDigits)
return false;
var start = response[0] is 'F' or 'f' ? 2 : 0;
if (start + FrequencyDigits > response.Length)
return false;
long value = 0;
for (var i = 0; i < FrequencyDigits; i++)
{
var c = response[start + i];
if (c is < '0' or > '9')
return false;
value = value * 10 + (c - '0');
}
hz = value;
return true;
}
public static bool TryGetModeCode(string mode, out char modeCode)
{
modeCode = default;
var upper = mode.Trim().ToUpperInvariant();
var code = upper switch
{
"LSB" or "DATA-LSB" => '1',
"USB" or "DATA-USB" => '2',
"CW" or "CW-U" => '3',
"CWR" or "CW-L" => '7',
"FM" or "DATA-FM" or "FM-DATA" => '4',
"FMN" => 'B',
"AM" => '5',
"AMN" => 'D',
_ => (char)0
};
if (code == 0)
return false;
modeCode = code;
return true;
}
public static bool IsFmMode(string mode)
{
var upper = mode.Trim().ToUpperInvariant();
return upper is "FM" or "FMN" or "DATA-FM" or "FM-DATA" or "C4FM";
}
public static bool TryGetCtcssIndex(double toneHz, out int zeroBasedIndex)
{
zeroBasedIndex = 0;
var best = -1;
var bestDiff = double.MaxValue;
for (var i = 0; i < CtcssTonesHz.Length; i++)
{
var diff = Math.Abs(CtcssTonesHz[i] - toneHz);
if (diff >= bestDiff)
continue;
bestDiff = diff;
best = i;
}
if (best < 0 || bestDiff > 0.15)
return false;
zeroBasedIndex = best;
return true;
}
}