Added namespace to FT8 v2

This commit is contained in:
Karlis Goba 2018-10-29 10:17:36 +02:00
parent a29e1f0221
commit 41e7aef8b8
5 changed files with 137 additions and 9 deletions

View file

@ -25,4 +25,7 @@ void genft8(const uint8_t *payload, uint8_t i3, uint8_t *itone);
// * codeword - array of 174 bits stored as 22 bytes (MSB first) // * codeword - array of 174 bits stored as 22 bytes (MSB first)
void encode174(const uint8_t *message, uint8_t *codeword); void encode174(const uint8_t *message, uint8_t *codeword);
uint16_t ft8_crc(uint8_t *message, int nBits); // Compute 12-bit CRC for a sequence of given number of bits
// [IN] message - byte sequence (MSB first)
// [IN] num_bits - number of bits in the sequence
uint16_t ft8_crc(uint8_t *message, int num_bits);

View file

@ -1,5 +1,7 @@
#include "encode.h" #include "encode.h"
namespace ft8_v2 {
constexpr int N = 174, K = 91, M = N-K; // Define the LDPC sizes constexpr int N = 174, K = 91, M = N-K; // Define the LDPC sizes
constexpr uint16_t POLYNOMIAL = 0x2757; // CRC-14 polynomial without the leading (MSB) 1 constexpr uint16_t POLYNOMIAL = 0x2757; // CRC-14 polynomial without the leading (MSB) 1
@ -214,10 +216,9 @@ uint16_t ft8_crc(uint8_t *message, int num_bits) {
// Generate FT8 tone sequence from payload data // Generate FT8 tone sequence from payload data
// [IN] payload - 9 byte array consisting of 72 bit payload (MSB first) // [IN] payload - 10 byte array consisting of 77 bit payload (MSB first)
// [IN] i3 - 3 bits containing message type (zero?)
// [OUT] itone - array of NN (79) bytes to store the generated tones (encoded as 0..7) // [OUT] itone - array of NN (79) bytes to store the generated tones (encoded as 0..7)
void genft8(const uint8_t *payload, uint8_t i3, uint8_t *itone) { void genft8(const uint8_t *payload, uint8_t *itone) {
uint8_t a91[12]; // Store 77 bits of payload + 14 bits CRC uint8_t a91[12]; // Store 77 bits of payload + 14 bits CRC
// Copy 77 bits of payload data // Copy 77 bits of payload data
@ -261,3 +262,5 @@ void genft8(const uint8_t *payload, uint8_t i3, uint8_t *itone) {
++k; ++k;
} }
} }
}; // namespace

34
encode_91.h Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
namespace ft8_v2 {
constexpr int ND = 58; // Data symbols
constexpr int NS = 21; // Sync symbols (3 @ Costas 7x7)
constexpr int NN = NS+ND; // Total channel symbols (79)
// Generate FT8 tone sequence from payload data
// [IN] payload - 9 byte array consisting of 72 bit payload
// [OUT] itone - array of NN (79) bytes to store the generated tones (encoded as 0..7)
void genft8(const uint8_t *payload, uint8_t *itone);
// Encode an 87-bit message and return a 174-bit codeword.
// The generator matrix has dimensions (87,87).
// The code is a (174,87) regular ldpc code with column weight 3.
// The code was generated using the PEG algorithm.
// After creating the codeword, the columns are re-ordered according to
// "colorder" to make the codeword compatible with the parity-check matrix
// Arguments:
// * message - array of 87 bits stored as 11 bytes (MSB first)
// * codeword - array of 174 bits stored as 22 bytes (MSB first)
void encode174(const uint8_t *message, uint8_t *codeword);
// Compute 14-bit CRC for a sequence of given number of bits
// [IN] message - byte sequence (MSB first)
// [IN] num_bits - number of bits in the sequence
uint16_t ft8_crc(uint8_t *message, int num_bits);
};

View file

@ -3,6 +3,8 @@
#include "text.h" #include "text.h"
namespace ft8_v2 {
// TODO: This is wasteful, should figure out something more elegant // TODO: This is wasteful, should figure out something more elegant
const char *A0 = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"; const char *A0 = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?";
const char *A1 = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *A1 = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@ -33,11 +35,12 @@ int32_t pack28(const char *callsign) {
if (starts_with(callsign, "CQ_")) { if (starts_with(callsign, "CQ_")) {
int nnum = 0, nlet = 0; int nnum = 0, nlet = 0;
// TODO:
// if(nnum.eq.3 .and. nlet.eq.0) then n28=3+nqsy // if(nnum.eq.3 .and. nlet.eq.0) then n28=3+nqsy
// if(nlet.ge.1 .and. nlet.le.4 .and. nnum.eq.0) then n28=3+1000+m // if(nlet.ge.1 .and. nlet.le.4 .and. nnum.eq.0) then n28=3+1000+m
} }
// Check for <...> callsign // TODO: Check for <...> callsign
// if(c13(1:1).eq.'<')then // if(c13(1:1).eq.'<')then
// call save_hash_call(c13,n10,n12,n22) !Save callsign in hash table // call save_hash_call(c13,n10,n12,n22) !Save callsign in hash table
// n28=NTOKENS + n22 // n28=NTOKENS + n22
@ -88,6 +91,7 @@ int32_t pack28(const char *callsign) {
//if (length > 13) return -1; //if (length > 13) return -1;
// TODO:
// Treat this as a nonstandard callsign: compute its 22-bit hash // Treat this as a nonstandard callsign: compute its 22-bit hash
// call save_hash_call(c13,n10,n12,n22) !Save callsign in hash table // call save_hash_call(c13,n10,n12,n22) !Save callsign in hash table
// n28=NTOKENS + n22 // n28=NTOKENS + n22
@ -109,12 +113,15 @@ bool chkcall(const char *call, char *bc) {
if (0 != strchr(call, '?')) return false; if (0 != strchr(call, '?')) return false;
if (length > 6 && 0 != strchr(call, '/')) return false; if (length > 6 && 0 != strchr(call, '/')) return false;
// TODO: implement suffix parsing (or rework?)
//bc=w(1:6) //bc=w(1:6)
//i0=index(w,'/') //i0=index(w,'/')
//if(max(i0-1,n1-i0).gt.6) go to 100 !Base call must be < 7 characters //if(max(i0-1,n1-i0).gt.6) go to 100 !Base call must be < 7 characters
//if(i0.ge.2 .and. i0.le.n1-1) then !Extract base call from compound call //if(i0.ge.2 .and. i0.le.n1-1) then !Extract base call from compound call
// if(i0-1.le.n1-i0) bc=w(i0+1:n1)//' ' // if(i0-1.le.n1-i0) bc=w(i0+1:n1)//' '
// if(i0-1.gt.n1-i0) bc=w(1:i0-1)//' ' // if(i0-1.gt.n1-i0) bc=w(1:i0-1)//' '
return true;
} }
@ -171,6 +178,8 @@ int pack77_1(const char *msg, uint8_t *b77) {
int32_t n28a = pack28(call1); int32_t n28a = pack28(call1);
int32_t n28b = pack28(call2); int32_t n28b = pack28(call2);
if (n28a < 0 || n28b < 0) return -1;
uint16_t igrid4; uint16_t igrid4;
@ -184,9 +193,10 @@ int pack77_1(const char *msg, uint8_t *b77) {
igrid4 = packgrid(0); igrid4 = packgrid(0);
} }
uint8_t i3 = 1; uint8_t i3 = 1; // No suffix or /R
// TODO: check for suffixes
// if(index(w(1),'/P').ge.4 .or. index(w(2),'/P').ge.4) i3=2 !Type 2, with "/P" // if(index(w(1),'/P').ge.4 .or. index(w(2),'/P').ge.4) i3=2 !Type 2, with "/P"
// if(index(w(1),'/P').ge.4 .or. index(w(1),'/R').ge.4) ipa=1 // if(index(w(1),'/P').ge.4 .or. index(w(1),'/R').ge.4) ipa=1
// if(index(w(2),'/P').ge.4 .or. index(w(2),'/R').ge.4) ipb=1 // if(index(w(2),'/P').ge.4 .or. index(w(2),'/R').ge.4) ipb=1
@ -194,9 +204,9 @@ int pack77_1(const char *msg, uint8_t *b77) {
n28a <<= 1; // ipa = 0 n28a <<= 1; // ipa = 0
n28b <<= 1; // ipb = 0 n28b <<= 1; // ipb = 0
// Pack into (28 + 1) + (28 + 1) + (1 + 15) + 3 bits
// write(c77,1000) n28a,ipa,n28b,ipb,ir,igrid4,i3 // write(c77,1000) n28a,ipa,n28b,ipb,ir,igrid4,i3
// 1000 format(2(b28.28,b1),b1,b15.15,b3.3) // 1000 format(2(b28.28,b1),b1,b15.15,b3.3)
// (28 + 1) + (28 + 1) + (1 + 15) + 3
b77[0] = (n28a >> 21); b77[0] = (n28a >> 21);
b77[1] = (n28a >> 13); b77[1] = (n28a >> 13);
@ -242,11 +252,14 @@ void packtext77(const char *c13, uint8_t *b71) {
} }
} }
int pack77(const char *msg, uint8_t *c77) { int pack77(const char *msg, uint8_t *c77) {
// Check Type 1 (Standard 77-bit message) or Type 2, with optional "/P" // Check Type 1 (Standard 77-bit message) or Type 2, with optional "/P"
//if (starts_with(msg, "CQ ")) { //if (starts_with(msg, "CQ ")) {
return pack77_1(msg, c77); return pack77_1(msg, c77);
//} //}
// TODO:
// Check 0.5 (telemetry) // Check 0.5 (telemetry)
// i3=0 n3=5 write(c77,1006) ntel,n3,i3 1006 format(b23.23,2b24.24,2b3.3) // i3=0 n3=5 write(c77,1006) ntel,n3,i3 1006 format(b23.23,2b24.24,2b3.3)
@ -257,4 +270,67 @@ int pack77(const char *msg, uint8_t *c77) {
// i3=0 n3=0 // i3=0 n3=0
// packtext77(msg(1:13),c77(1:71)) // packtext77(msg(1:13),c77(1:71))
// write(c77(72:77),'(2b3.3)') n3,i3 // write(c77(72:77),'(2b3.3)') n3,i3
} }
}; // namespace
#ifdef UNIT_TEST
#include <iostream>
using namespace std;
bool test1() {
const char *inputs[] = {
"",
" ",
"ABC",
"A9",
"L9A",
"L7BC",
"L0ABC",
"LL3JG",
"LL3AJG",
"CQ ",
0
};
for (int i = 0; inputs[i]; ++i) {
int32_t result = ft8_v2::pack28(inputs[i]);
printf("pack28(\"%s\") = %d\n", inputs[i], result);
}
return true;
}
bool test2() {
const char *inputs[] = {
"CQ LL3JG",
"CQ LL3JG KO26",
"L0UAA LL3JG KO26",
"L0UAA LL3JG +02",
"L0UAA LL3JG RRR",
"L0UAA LL3JG 73",
0
};
for (int i = 0; inputs[i]; ++i) {
uint8_t result[10];
int rc = ft8_v2::pack77_1(inputs[i], result);
printf("pack77_1(\"%s\") = %d\t[", inputs[i], rc);
for (int j = 0; j < 10; ++j) {
printf("%02x ", result[j]);
}
printf("]\n");
}
return true;
}
int main() {
test1();
test2();
return 0;
}
#endif

12
pack_77.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
namespace ft8_v2 {
// Pack FT8 text message into 72 bits
// [IN] msg - FT8 message (e.g. "CQ TE5T KN01")
// [OUT] c77 - 10 byte array to store the 77 bit payload (MSB first)
int pack77(const char *msg, uint8_t *c77)
};