Updates to API for greater user input.

pull/1/head
Mark Jessop 2020-06-15 18:38:24 +09:30
rodzic e6fc371e03
commit 73732f9800
3 zmienionych plików z 187 dodań i 46 usunięć

Wyświetl plik

@ -36,9 +36,9 @@
#include "horus_l2.h"
#define MAX_UW_LENGTH 100
#define HORUS_API_VERSION 1 /* unique number that is bumped if API changes */
#define HORUS_BINARY_NUM_BITS 360 /* fixed number of bytes in binary payload */
#define HORUS_BINARY_NUM_PAYLOAD_BYTES 22 /* fixed number of bytes in binary payload */
#define HORUS_API_VERSION 2 /* unique number that is bumped if API changes */
struct horus {
int mode;
@ -68,16 +68,41 @@ int8_t uw_horus_rtty[] = {
0,0,1,0,0,1,0,1,1,0
};
/* Unique word for Horus Binary */
/* Unique word for Horus Binary V1 */
int8_t uw_horus_binary[] = {
int8_t uw_horus_binary_v1[] = {
0,0,1,0,0,1,0,0,
0,0,1,0,0,1,0,0
};
struct horus *horus_open (int mode, int Rs) {
int i;
assert((mode == HORUS_MODE_RTTY) || (mode == HORUS_MODE_BINARY));
/* Unique word for Horus Binary V2 128/256 bit modes (Last row in the 32x32 Hadamard matrix) */
int8_t uw_horus_binary_v2[] = {
1, 0, 0, 1, 0, 1, 1, 0, // 0x96
0, 1, 1, 0, 1, 0, 0, 1, // 0x69
0, 1, 1, 0, 1, 0, 0, 1, // 0x69
1, 0, 0, 1, 0, 1, 1, 0 // 0x96
};
struct horus *horus_open (int mode) {
assert((mode == HORUS_MODE_RTTY) || (mode == HORUS_MODE_BINARY_V1) || (mode == HORUS_MODE_BINARY_V2_256BIT) || (mode == HORUS_MODE_BINARY_V2_128BIT));
if (mode == HORUS_MODE_RTTY){
// RTTY Mode defaults - 100 baud, no assumptions about tone spacing.
return horus_open_advanced(HORUS_MODE_RTTY, HORUS_RTTY_DEFAULT_BAUD, -1);
} else {
// Placeholder until we have more definition of the new modes.
// Legacy Horus Binary Mode defaults - 100 baud, Disable mask estimation.
return horus_open_advanced(HORUS_MODE_BINARY_V1, HORUS_BINARY_V1_DEFAULT_BAUD, -1);
}
}
struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing) {
int i, mask;
assert((mode == HORUS_MODE_RTTY) || (mode == HORUS_MODE_BINARY_V1) || (mode == HORUS_MODE_BINARY_V2_256BIT) || (mode == HORUS_MODE_BINARY_V2_128BIT));
struct horus *hstates = (struct horus *)malloc(sizeof(struct horus));
assert(hstates != NULL);
@ -85,8 +110,23 @@ struct horus *horus_open (int mode, int Rs) {
hstates->Fs = 48000; hstates->Rs = Rs; hstates->verbose = 0; hstates->mode = mode;
if (mode == HORUS_MODE_RTTY) {
// Parameter setup for RTTY Reception
hstates->mFSK = 2;
hstates->max_packet_len = 1000;
hstates->max_packet_len = HORUS_RTTY_NUM_BITS;
// If baud rate not provided, use default
if (hstates->Rs == -1){
hstates->Rs = HORUS_RTTY_DEFAULT_BAUD;
}
if (tx_tone_spacing == -1){
// No tone spacing provided. Use dummy value to keep fsk modem happy, and disable mask estimation.
tx_tone_spacing = 2*hstates->Rs;
mask = 0;
} else {
mask = 1;
}
/* map UW to make it easier to search for */
@ -98,19 +138,42 @@ struct horus *horus_open (int mode, int Rs) {
hstates->rx_bits_len = hstates->max_packet_len;
}
if (mode == HORUS_MODE_BINARY) {
if (mode == HORUS_MODE_BINARY_V1) {
// Parameter setup for the Legacy Horus Binary Mode (22 byte frames, Golay encoding)
hstates->mFSK = 4;
hstates->max_packet_len = HORUS_BINARY_NUM_BITS;
for (i=0; i<sizeof(uw_horus_binary); i++) {
hstates->uw[i] = 2*uw_horus_binary[i] - 1;
hstates->max_packet_len = HORUS_BINARY_V1_NUM_CODED_BITS;
// If baud rate not provided, use default
if (hstates->Rs == -1){
hstates->Rs = HORUS_BINARY_V1_DEFAULT_BAUD;
}
hstates->uw_len = sizeof(uw_horus_binary);
hstates->uw_thresh = sizeof(uw_horus_binary) - 2; /* allow a few bit errors in UW detection */
if (tx_tone_spacing == -1){
// No tone spacing provided. Disable mask estimation, and use the default tone spacing value as a dummy value.
tx_tone_spacing = HORUS_BINARY_V1_DEFAULT_TONE_SPACING;
mask = 0;
} else {
// Tone spacing provided, enable mask estimation.
mask = 1;
}
for (i=0; i<sizeof(uw_horus_binary_v1); i++) {
hstates->uw[i] = 2*uw_horus_binary_v1[i] - 1;
}
hstates->uw_len = sizeof(uw_horus_binary_v1);
hstates->uw_thresh = sizeof(uw_horus_binary_v1) - 2; /* allow a few bit errors in UW detection */
horus_l2_init();
hstates->rx_bits_len = hstates->max_packet_len;
}
hstates->fsk = fsk_create(hstates->Fs, hstates->Rs, hstates->mFSK, 1000, 2*hstates->Rs);
// TODO: Horus 256/128-bit modes here.
// Create the FSK modedm struct. Note that the low-tone-frequency parameter is unused.
#define UNUSED 1000
hstates->fsk = fsk_create(hstates->Fs, hstates->Rs, hstates->mFSK, UNUSED, tx_tone_spacing);
// Set/disable the mask estimator depending on if tx_tone_spacing was provided (refer above)
fsk_set_freq_est_alg(hstates->fsk, mask);
/* allocate enough room for two packets so we know there will be
one complete packet if we find a UW at start */
@ -275,7 +338,7 @@ int extract_horus_rtty(struct horus *hstates, char ascii_out[], int uw_loc) {
}
int extract_horus_binary(struct horus *hstates, char hex_out[], int uw_loc) {
int extract_horus_binary_v1(struct horus *hstates, char hex_out[], int uw_loc) {
const int nfield = 8; /* 8 bit binary */
int st = uw_loc; /* first bit of first char */
int en = uw_loc + hstates->max_packet_len; /* last bit of max length packet */
@ -313,13 +376,13 @@ int extract_horus_binary(struct horus *hstates, char hex_out[], int uw_loc) {
fprintf(stderr, "\n");
}
uint8_t payload_bytes[HORUS_BINARY_NUM_PAYLOAD_BYTES];
horus_l2_decode_rx_packet(payload_bytes, rxpacket, HORUS_BINARY_NUM_PAYLOAD_BYTES);
uint8_t payload_bytes[HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES];
horus_l2_decode_rx_packet(payload_bytes, rxpacket, HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES);
uint16_t crc_tx, crc_rx;
crc_rx = horus_l2_gen_crc16(payload_bytes, HORUS_BINARY_NUM_PAYLOAD_BYTES-2);
crc_tx = (uint16_t)payload_bytes[HORUS_BINARY_NUM_PAYLOAD_BYTES-2] +
((uint16_t)payload_bytes[HORUS_BINARY_NUM_PAYLOAD_BYTES-1]<<8);
crc_rx = horus_l2_gen_crc16(payload_bytes, HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES-2);
crc_tx = (uint16_t)payload_bytes[HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES-2] +
((uint16_t)payload_bytes[HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES-1]<<8);
if (hstates->verbose) {
fprintf(stderr, " extract_horus_binary crc_tx: %04X crc_rx: %04X\n", crc_tx, crc_rx);
@ -329,7 +392,7 @@ int extract_horus_binary(struct horus *hstates, char hex_out[], int uw_loc) {
hex_out[0] = 0;
char hex[3];
for (b=0; b<HORUS_BINARY_NUM_PAYLOAD_BYTES; b++) {
for (b=0; b<HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES; b++) {
sprintf(hex, "%02X", payload_bytes[b]);
strcat(hex_out, hex);
}
@ -343,7 +406,7 @@ int extract_horus_binary(struct horus *hstates, char hex_out[], int uw_loc) {
hstates->crc_ok = (crc_tx == crc_rx);
if ( hstates->crc_ok) {
hstates->total_payload_bits += HORUS_BINARY_NUM_PAYLOAD_BYTES;
hstates->total_payload_bits += HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES;
}
return hstates->crc_ok;
}
@ -377,13 +440,13 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad
COMP *demod_in_comp = (COMP*)malloc(sizeof(COMP)*hstates->fsk->nin);
for (i=0; i<hstates->fsk->nin; i++) {
if (quadrature) {
demod_in_comp[i].real = demod_in[i * 2];
demod_in_comp[i].imag = demod_in[i * 2 + 1];
} else {
demod_in_comp[i].real = demod_in[i];
demod_in_comp[i].imag = 0;
}
if (quadrature) {
demod_in_comp[i].real = demod_in[i * 2];
demod_in_comp[i].imag = demod_in[i * 2 + 1];
} else {
demod_in_comp[i].real = demod_in[i];
demod_in_comp[i].imag = 0;
}
}
fsk_demod(hstates->fsk, &hstates->rx_bits[rx_bits_len-Nbits], demod_in_comp);
free(demod_in_comp);
@ -402,8 +465,8 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad
if (hstates->mode == HORUS_MODE_RTTY) {
packet_detected = extract_horus_rtty(hstates, ascii_out, uw_loc);
}
if (hstates->mode == HORUS_MODE_BINARY) {
packet_detected = extract_horus_binary(hstates, ascii_out, uw_loc);
if (hstates->mode == HORUS_MODE_BINARY_V1) {
packet_detected = extract_horus_binary_v1(hstates, ascii_out, uw_loc);
//#define DUMP_BINARY_PACKET
#ifdef DUMP_BINARY_PACKET
FILE *f = fopen("packetbits.txt", "wt"); assert(f != NULL);
@ -448,9 +511,14 @@ int horus_get_max_ascii_out_len(struct horus *hstates) {
if (hstates->mode == HORUS_MODE_RTTY) {
return hstates->max_packet_len/10; /* 7 bit ASCII, plus 3 sync bits */
}
if (hstates->mode == HORUS_MODE_BINARY) {
return (HORUS_BINARY_NUM_PAYLOAD_BYTES*2+1); /* Hexadecimal encoded */
//return HORUS_BINARY_NUM_PAYLOAD_BYTES;
if (hstates->mode == HORUS_MODE_BINARY_V1) {
return (HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES*2+1); /* Hexadecimal encoded */
}
if (hstates->mode == HORUS_MODE_BINARY_V2_256BIT) {
return (HORUS_BINARY_V2_256BIT_NUM_UNCODED_PAYLOAD_BYTES*2+1); /* Hexadecimal encoded */
}
if (hstates->mode == HORUS_MODE_BINARY_V2_128BIT) {
return (HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES*2+1); /* Hexadecimal encoded */
}
assert(0); /* should never get here */
return 0;

Wyświetl plik

@ -35,20 +35,78 @@
#include <stdint.h>
#include "modem_stats.h"
#define HORUS_MODE_BINARY 0
#define HORUS_MODE_RTTY 1
/* Horus API Modes */
#define HORUS_MODE_BINARY_V1 0 // Legacy binary mode
#define HORUS_MODE_BINARY_V2_256BIT 1 // New 256-bit LDPC-encoded mode
#define HORUS_MODE_BINARY_V2_128BIT 2 // New 128-bit LDPC-encoded mode
#define HORUS_MODE_RTTY 99 // RTTY Decoding
// Settings for Legacy Horus Binary Mode (Golay Encoding)
#define HORUS_BINARY_V1_NUM_CODED_BITS 360
#define HORUS_BINARY_V1_NUM_UNCODED_PAYLOAD_BYTES 22
#define HORUS_BINARY_V1_DEFAULT_BAUD 100
#define HORUS_BINARY_V1_DEFAULT_TONE_SPACING 270 // This is the minimum tone spacing possible on the RS41
// reference implementation of this modem.
// Note that mask estimation is turned off by default for
// this mode, and hence this spacing is not used.
// Settings for Horus Binary 256-bit mode (LDPC Encoding, r=1/3)
#define HORUS_BINARY_V2_256BIT_NUM_CODED_BITS 768
#define HORUS_BINARY_V2_256BIT_NUM_UNCODED_PAYLOAD_BYTES 32
#define HORUS_BINARY_V2_256BIT_DEFAULT_BAUD 100
#define HORUS_BINARY_V2_256BIT_DEFAULT_TONE_SPACING 270
// Settings for Horus Binary 128-bit mode (LDPC Encoding, r=1/3)
#define HORUS_BINARY_V2_128BIT_NUM_CODED_BITS 384
#define HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES 16
#define HORUS_BINARY_V2_128BIT_DEFAULT_BAUD 25
#define HORUS_BINARY_V2_128BIT_DEFAULT_TONE_SPACING 270
// Settings for RTTY Decoder
#define HORUS_RTTY_NUM_BITS 1000 // Limit the RTTY decoder to 100 characters per line (frame).
#define HORUS_RTTY_DEFAULT_BAUD 100
struct horus;
struct MODEM_STATS;
struct horus *horus_open (int mode, int Rs);
/*
* Create an Horus Demod config/state struct using default mode parameters.
*
* int mode - Horus Mode Type (refer list above)
*/
struct horus *horus_open (int mode);
/*
* Create an Horus Demod config/state struct with more customizations.
*
* int mode - Horus Mode Type (refer list above)
* int Rs - Symbol Rate (Hz). Set to -1 to use the default value for the mode (refer above)
* int tx_tone_spacing - FSK Tone Spacing, to configure mask estimator. Set to -1 to disable mask estimator.
*/
struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing);
/*
* Close a Horus demodulator struct and free memory.
*/
void horus_close (struct horus *hstates);
/* call before horus_rx() to determine how many shorts to pass in */
uint32_t horus_nin (struct horus *hstates);
/* returns 1 if ascii_out[] is valid */
/*
* Demodulate some number of Horus modem samples. The number of samples to be
* demodulated can be found by calling horus_nin().
*
* Returns 1 if the data in ascii_out[] is valid.
*
* struct horus *hstates - Horus API config/state struct, set up by horus_open / horus_open_advanced
* char ascii_out[] - Buffer for returned packet / text.
* short fsk_in[] - nin samples of modulated FSK.
* int quadrature - Set to 1 if input samples are complex samples.
*/
int horus_rx (struct horus *hstates, char ascii_out[], short demod_in[], int quadrature);

Wyświetl plik

@ -55,7 +55,8 @@ int main(int argc, char *argv[]) {
int quadrature = 0;
int fsk_lower = -1;
int fsk_upper = -1;
int Rs = 100;
int Rs = -1;
int tone_spacing = -1;
stats_loop = 0;
stats_rate = 8;
@ -69,6 +70,7 @@ int main(int argc, char *argv[]) {
{"help", no_argument, 0, 'h'},
{"mode", required_argument, 0, 'm'},
{"rate", optional_argument, 0, 'r'},
{"tonespacing", optional_argument, 0, 's'},
{"stats", optional_argument, 0, 't'},
{"fsk_lower", optional_argument, 0, 'b'},
{"fsk_upper", optional_argument, 0, 'u'},
@ -83,8 +85,15 @@ int main(int argc, char *argv[]) {
mode = HORUS_MODE_RTTY;
}
if ((strcmp(optarg, "BINARY") == 0) || (strcmp(optarg, "binary") == 0)) {
mode = HORUS_MODE_BINARY;
mode = HORUS_MODE_BINARY_V1;
}
// Commented out until these are implemented.
// if ((strcmp(optarg, "256BIT") == 0) || (strcmp(optarg, "256bit") == 0)) {
// mode = HORUS_MODE_BINARY_256BIT;
// }
// if ((strcmp(optarg, "128BIT") == 0) || (strcmp(optarg, "128bit") == 0)) {
// mode = HORUS_MODE_BINARY_128BIT;
// }
if (mode == -1) {
fprintf(stderr, "use --mode RTTY or --mode binary\n");
exit(1);
@ -127,6 +136,11 @@ int main(int argc, char *argv[]) {
Rs = atoi(optarg);
}
break;
case 's':
if (optarg != NULL){
tone_spacing = atoi(optarg);
}
break;
break;
}
}
@ -138,7 +152,7 @@ int main(int argc, char *argv[]) {
goto helpmsg;
}
if( (argc - dx) > 5) {
if( (argc - dx) > 6) {
fprintf(stderr, "Too many arguments\n");
helpmsg:
fprintf(stderr,"usage: %s -m RTTY|binary [-q] [-v] [-c] [-t [r]] InputModemRawFile OutputAsciiFile\n",argv[0]);
@ -146,7 +160,8 @@ int main(int argc, char *argv[]) {
fprintf(stderr,"InputModemRawFile 48 kHz 16 bit shorts real modem signal from radio\n");
fprintf(stderr," -m RTTY|binary\n");
fprintf(stderr,"--mode=RTTY|binary RTTY or binary Horus protcols\n");
fprintf(stderr,"--rate=[Rs] Modem baud rate. Default: 100\n");
fprintf(stderr,"--rate=[Rs] Customise modem baud rate. Default: (depends on mode) \n");
fprintf(stderr,"--tonespacing=[tone_spacing] Transmitter Tone Spacing (Hz) Default: Not used.\n");
fprintf(stderr," -t[r] --stats=[r] Print out modem statistics to stderr in JSON.\n");
fprintf(stderr," r, if provided, sets the number of modem frames\n"
" between statistic printouts\n");
@ -180,7 +195,7 @@ int main(int argc, char *argv[]) {
/* end command line processing */
hstates = horus_open(mode, Rs);
hstates = horus_open_advanced(mode, Rs, tone_spacing);
horus_set_verbose(hstates, verbose);
if (hstates == NULL) {