FT8 demod: support for types 0.5 and 5 messages

This commit is contained in:
f4exb 2023-01-28 22:45:07 +01:00
parent 5980dda8a9
commit f63f1270ba
3 changed files with 121 additions and 16 deletions

View File

@ -145,11 +145,8 @@ std::string Packing::unpackcall(int x)
// unpack a 15-bit grid square &c.
// 77-bit version, from inspection of packjt77.f90.
// ir is the bit after the two 28+1-bit callee/caller.
// i3 is the message type, usually 1.
std::string Packing::unpackgrid(int ng, int ir, int i3)
std::string Packing::unpackgrid15(int ng, int ir)
{
(void) i3;
if (ng < NGBASE)
{
// maidenhead grid system:
@ -203,6 +200,31 @@ std::string Packing::unpackgrid(int ng, int ir, int i3)
return std::string(tmp);
}
std::string Packing::unpackgrid25(int ng)
{
int x1 = ng / (18 * 10 * 10 * 25 * 25);
ng %= (18 * 10 * 10 * 25 * 25);
int x2 = ng / (10 * 10 * 25 * 25);
ng %= (10 * 10 * 25 * 25);
int x3 = ng / (10 * 25 * 25);
ng %= (10 * 25 * 25);
int x4 = ng / (25 * 25);
ng %= (25 * 25);
int x5 = ng / (25);
ng %= (25);
int x6 = ng;
char tmp[7];
tmp[0] = 'A' + x1;
tmp[1] = 'A' + x2;
tmp[2] = '0' + x3;
tmp[3] = '0' + x4;
tmp[4] = 'A' + x5;
tmp[5] = 'A' + x6;
tmp[6] = '\0';
return std::string(tmp);
}
void Packing::remember_call(std::string call)
{
hashes_mu.lock();
@ -329,7 +351,7 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal
call1str = trim(unpackcall(call1));
call2str = trim(unpackcall(call2));
locstr = unpackgrid(grid, ir, i3);
locstr = unpackgrid15(grid, ir);
remember_call(call1str);
remember_call(call2str);
@ -339,6 +361,52 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal
return call1str + (rover1 ? pr : "") + " " + call2str + (rover2 ? pr : "") + " " + locstr;
}
std::string Packing::unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr)
{
int x12 = un64(a77, 0, 12);
// 12-bit hash
hashes_mu.lock();
std::string ocall;
if (hashes12.count(x12) > 0) {
ocall = hashes12[x12];
} else {
ocall = "<...12>";
}
call1str = std::string(ocall);
int x22 = un64(a77, 12, 22);
if (hashes22.count(x22) > 0) {
ocall = hashes12[x22];
} else {
ocall = "<...22>";
}
call2str = std::string(ocall);
// mext bit is alway for R
int i = 12+ 22 +1;
// r3
int rst = un64(a77, i, 3);
rst = 52 + 10 * rst;
i += 3;
int qsonb = un64(a77, i, 11);
char report[16];
sprintf(report, "%d%04d", rst, qsonb);
i += 11;
// g25
int ng = un64(a77, i, 25);
locstr = unpackgrid25(ng);
std::string msg;
msg = call1str + " " + call2str + " " + std::string(report) + " " + locstr;
call1str += " " + std::string(report);
return msg;
}
// free text
// 71 bits, 13 characters, each one of 42 choices.
// reversed.
@ -408,6 +476,30 @@ std::string Packing::unpack_0_1(int a77[], std::string& call1str, std::string& c
return msg;
}
std::string Packing::unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr)
{
(void) call2str;
(void) locstr;
const char *cc = "0123456789ABCDEF";
std::string msg = "123456789ABCDEF012";
// first digit is on 3 bits
int d0 = un64(a77, 0, 3);
msg[17] = cc[d0];
// 17 hexadecimal digits = 17*4 = 68 bits
boost::multiprecision::int128_t x = un128(a77, 3, 68);
for (int i = 0; i < 17; i++)
{
msg[17 - 1 - i] = cc[(int) (x % 4)];
x = x / 4;
}
call1str = msg;
return msg;
}
// ARRL RTTY Round-Up states/provinces
const char *Packing::ru_states[] = {
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA",
@ -589,6 +681,12 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s
return unpack_0_3(a77, n3, call1, call2, loc);
}
if (i3 == 0 && n3 == 5)
{
// telemetry
return unpack_0_5(a77, call1, call2, loc);
}
if (i3 == 1 || i3 == 2)
{
// ordinary message or EU VHF
@ -607,7 +705,11 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s
return unpack_4(a77, call1, call2, loc);
}
// TODO: i3 == 5 EU VHF missing
if (i3 == 5)
{
// EU VHF with 6 digits locator
return unpack_5(a77, call1, call2, loc);
}
call1 = "UNK";
sprintf(tmp, "UNK i3=%d n3=%d", i3, n3);

View File

@ -38,16 +38,19 @@ public:
private:
static int ihashcall(std::string call, int m);
std::string unpackcall(int x);
std::string unpackgrid(int ng, int ir, int i3);
std::string unpackgrid15(int ng, int ir);
std::string unpackgrid25(int ng);
void remember_call(std::string call);
std::string unpack_0_0(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
std::string unpack_0_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
// 0.3 and 0.4
std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr);
std::string unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
// 1 and 2
std::string unpack_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
std::string unpack_3(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
std::string unpack_4(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
std::string unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr);
QRecursiveMutex hashes_mu;
std::map<int, std::string> hashes10;

View File

@ -154,9 +154,9 @@ Example:
- **3**: SNR in 2.5 kHz bandwidth
- **4**: Message start delay in seconds from standard sequence start
- **5**: Message carrier shift from base frequency in Hz
- **6**: First callsign area. May contain spaces (ex: "CQ DX")
- **7**: Second callsign area
- **8**: Locator area
- **6**: First callsign area. May contain spaces (ex: "CQ DX"). Note that for messages types 0.1 and 5 it is slighlty different from the standard (See C.10)
- **7**: Second callsign area and is always a callsign. This might be slighlty different from the standard (see above)
- **8**: Locator area maybe a 4 or 6 digit locator, a report, acknowledgement (RRR) or a greetings (RR73, 73)
- **9**: Decoder information if any
The splitting and naming of files is different from WSJT-X scheme.
@ -184,23 +184,23 @@ Displays the received messages in a table which columns are the following:
- **UTC**: UTC time in HHmmss format of the FT8 slot
- **Typ**: Message type according to the i3.n3 format described in the protocol (see reference at the top):
- **0.0**: Free text
- **0.1**: DXpedition. Message carries two compacted messages (one for RR73 and one for report to two different callees). They will be de-compacted for dispplay.
- **0.0**: Free text. The first call area is populated with the free text. second call and locator areas are left blank.
- **0.1**: DXpedition. Message carries two compacted messages (one for RR73 and one for report to two different callees). They will be de-compacted in two separate messages for display. This is different from the standard that yields a single message.
- **0.3**: ARRL field day
- **0.4**: ARRL field day
- **0.5**: Telemetry
- **1**: Standard message (the most common)
- **2**: European VHF (4 char locator) minor change to standard message
- **2**: European VHF (4 char locator) minor change to standard message above
- **3**: Russian RTTY
- **4**: Non standard call
- **5**: European VHF (6 char locator)
- **5**: European VHF (6 char locator). The report + QSO number is appended to first call area not to pollute the second call area which contains only a callsign, This is slightly diffrent from the standard.
- **P**: LDPC decoder pass index that was successful (0 to 2) as there are 3 passes
- **OKb**: Number of correct bits in the message before FEC correction. Maximum is 174 in which case no FEC would be needed.
- **dt**: Message start time shift in seconds from standard FT8 time slot
- **df**: Message frequency shift in Hz from base frequency. This is the shift of the lowest frequency symbol
- **SNR**: Signal to noise ratio in dB transposed in a 2.5 kHz bandwidth (WSJT-X standard). The actual SNR is this value plus 26 dB.
- **Call1**: This is the first call area and may contain the caller callsign, a CQ or a custom 13 character message in which case the second call and locator areas are empty
- **Call2**: This is the second call area and will contain the callsign of the responding station
- **Call1**: This is the first call area and may contain the caller callsign, a CQ or a custom 13 character message in which case the second call and locator areas are empty. It may be slightly different from the standard for message type 5 (see above).
- **Call2**: This is the second call area and will contain the callsign of the responding station. This is always a callsign and this may differ slightly from the standard for messages type 5 (see above).
- **Loc**: Locator area which contains the 4 character Maidenhead locator, a report, an acknowledgement (RRR) or a greetings (73 or RR73)
- **Info**: FT8 decoder information if any. If OSD is active (see C.1.3) and OSD was activated it reports the OSD decoder status as `OSD-N-MM` where N is the OSD depth reached and MM is the number of correct LDPC bits.