diff --git a/src/horus_api.c b/src/horus_api.c index 82c4889..e28dfdc 100644 --- a/src/horus_api.c +++ b/src/horus_api.c @@ -64,21 +64,17 @@ RTTY Unique word = $ characters, repeated at least 2 times. $ = (0)010 0100 Reversed = 0010010(0) */ - +int8_t uw_horus_rtty_7N1[] = { + 0,0,1,0,0,1,0,1,0, + 0,0,1,0,0,1,0,1,0, +}; int8_t uw_horus_rtty_7N2[] = { 0,0,1,0,0,1,0,1,1,0, 0,0,1,0,0,1,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0 }; - int8_t uw_horus_rtty_8N2[] = { 0,0,1,0,0,1,0,0,1,1,0, 0,0,1,0,0,1,0,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0, -// 0,0,1,0,0,1,0,1,1,0 }; /* Unique word for Horus Binary V1 */ @@ -101,28 +97,73 @@ int8_t uw_horus_binary_v2[] = { struct horus *horus_open (int mode) { - assert((mode == HORUS_MODE_RTTY_7N2) || (mode == HORUS_MODE_BINARY_V1) || (mode == HORUS_MODE_BINARY_V2_256BIT) || (mode == HORUS_MODE_BINARY_V2_128BIT)); + assert((mode == HORUS_MODE_RTTY_7N1) || (mode == HORUS_MODE_RTTY_7N2) || (mode == HORUS_MODE_RTTY_8N2) || (mode == HORUS_MODE_BINARY_V1) || (mode == HORUS_MODE_BINARY_V2_256BIT) || (mode == HORUS_MODE_BINARY_V2_128BIT)); + if (mode == HORUS_MODE_RTTY_7N1){ + // RTTY Mode defaults - 100 baud, no assumptions about tone spacing. + return horus_open_advanced(HORUS_MODE_RTTY_7N1, HORUS_RTTY_DEFAULT_BAUD, -1); + } if (mode == HORUS_MODE_RTTY_7N2){ // RTTY Mode defaults - 100 baud, no assumptions about tone spacing. return horus_open_advanced(HORUS_MODE_RTTY_7N2, HORUS_RTTY_DEFAULT_BAUD, -1); - } else { - // Placeholder until we have more definition of the new modes. + } + if (mode == HORUS_MODE_RTTY_8N2){ + // RTTY Mode defaults - 100 baud, no assumptions about tone spacing. + return horus_open_advanced(HORUS_MODE_RTTY_8N2, HORUS_RTTY_DEFAULT_BAUD, -1); + } + if (mode == HORUS_MODE_BINARY_V1){ // Legacy Horus Binary Mode defaults - 100 baud, Disable mask estimation. return horus_open_advanced(HORUS_MODE_BINARY_V1, HORUS_BINARY_V1_DEFAULT_BAUD, -1); } + if (mode == HORUS_MODE_BINARY_V2_128BIT){ + // V2 Horus Binary Mode defaults - 100 baud, Disable mask estimation. + return horus_open_advanced(HORUS_MODE_BINARY_V2_128BIT, HORUS_BINARY_V2_128BIT_DEFAULT_BAUD, -1); + } + if (mode == HORUS_MODE_BINARY_V2_256BIT){ + // V2 Horus Binary Mode defaults - 100 baud, Disable mask estimation. + return horus_open_advanced(HORUS_MODE_BINARY_V2_256BIT, HORUS_BINARY_V2_256BIT_DEFAULT_BAUD, -1); + } } struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing) { int i, mask; - assert((mode == HORUS_MODE_RTTY_7N2) || (mode == HORUS_MODE_RTTY_8N2) || (mode == HORUS_MODE_BINARY_V1) || (mode == HORUS_MODE_BINARY_V2_256BIT) || (mode == HORUS_MODE_BINARY_V2_128BIT)); + assert((mode == HORUS_MODE_RTTY_7N1) || (mode == HORUS_MODE_RTTY_7N2) || (mode == HORUS_MODE_RTTY_8N2) || (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); hstates->Fs = 48000; hstates->Rs = Rs; hstates->verbose = 0; hstates->mode = mode; + if (mode == HORUS_MODE_RTTY_7N1) { + // Parameter setup for RTTY 7N2 Reception + + hstates->mFSK = 2; + hstates->max_packet_len = HORUS_RTTY_7N1_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 */ + + for (i=0; iuw[i] = 2*uw_horus_rtty_7N1[i] - 1; + } + hstates->uw_len = sizeof(uw_horus_rtty_7N1); + hstates->uw_thresh = sizeof(uw_horus_rtty_7N1) - 2; /* allow a few bit errors in UW detection */ + hstates->rx_bits_len = hstates->max_packet_len; + } + if (mode == HORUS_MODE_RTTY_7N2) { // Parameter setup for RTTY 7N2 Reception @@ -742,6 +783,19 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad /* OK we have found a unique word, and therefore the start of a packet, so lets try to extract valid packets */ + if (hstates->mode == HORUS_MODE_RTTY_7N1) { + packet_detected = extract_horus_rtty(hstates, ascii_out, uw_loc, 7, 1); + + if (packet_detected){ + // If we have found a packet, advance the bits enough that we don't detect the + // same packet again, if it has more than 2x $$s. + // NEED TO CHECK THIS DOESN'T CAUSE SEGFAULTS! + for(i=0,j=100; i<100; i++,j++) { + hstates->rx_bits[i] = hstates->rx_bits[j]; + hstates->soft_bits[i] = hstates->soft_bits[j]; + } + } + } if (hstates->mode == HORUS_MODE_RTTY_7N2) { packet_detected = extract_horus_rtty(hstates, ascii_out, uw_loc, 7, 2); @@ -817,6 +871,9 @@ int horus_get_max_demod_in(struct horus *hstates) { int horus_get_max_ascii_out_len(struct horus *hstates) { assert(hstates != NULL); + if (hstates->mode == HORUS_MODE_RTTY_7N1) { + return hstates->max_packet_len/9; /* 7 bit ASCII, plus 3 sync bits */ + } if (hstates->mode == HORUS_MODE_RTTY_7N2) { return hstates->max_packet_len/10; /* 7 bit ASCII, plus 3 sync bits */ } diff --git a/src/horus_api.h b/src/horus_api.h index 8b6ba26..a786c2a 100644 --- a/src/horus_api.h +++ b/src/horus_api.h @@ -39,6 +39,7 @@ #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_7N1 89 // RTTY Decoding - 7N1 #define HORUS_MODE_RTTY_7N2 90 // RTTY Decoding - 7N2 #define HORUS_MODE_RTTY_8N2 91 // RTTY Decoding - 8N2 @@ -66,6 +67,7 @@ // Settings for RTTY Decoder #define HORUS_RTTY_MAX_CHARS 120 +#define HORUS_RTTY_7N1_NUM_BITS (HORUS_RTTY_MAX_CHARS*9) #define HORUS_RTTY_7N2_NUM_BITS (HORUS_RTTY_MAX_CHARS*10) #define HORUS_RTTY_8N2_NUM_BITS (HORUS_RTTY_MAX_CHARS*11) #define HORUS_RTTY_DEFAULT_BAUD 100 diff --git a/src/horus_demod.c b/src/horus_demod.c index cba1431..daf5461 100644 --- a/src/horus_demod.c +++ b/src/horus_demod.c @@ -81,9 +81,12 @@ int main(int argc, char *argv[]) { switch(o) { case 'm': - if ((strcmp(optarg, "RTTY") == 0) || (strcmp(optarg, "rtty") == 0)) { + if ((strcmp(optarg, "RTTY") == 0) || (strcmp(optarg, "rtty") == 0) || (strcmp(optarg, "RTTY7N2") == 0) || (strcmp(optarg, "rtty7n2") == 0)) { mode = HORUS_MODE_RTTY_7N2; } + if ((strcmp(optarg, "RTTY7N1") == 0) || (strcmp(optarg, "rtty7n1") == 0)) { + mode = HORUS_MODE_RTTY_7N1; + } if ((strcmp(optarg, "RTTY8N2") == 0) || (strcmp(optarg, "rtty8n2") == 0)) { mode = HORUS_MODE_RTTY_8N2; } diff --git a/src/horus_l2.c b/src/horus_l2.c index 91509eb..07d72c2 100644 --- a/src/horus_l2.c +++ b/src/horus_l2.c @@ -11,7 +11,7 @@ 1/ Unit test on a PC: - $ gcc horus_l2.c -o horus_l2 -Wall -DHORUS_L2_UNITTEST + $ gcc horus_l2.c golay23.c H_128_384_23.c H_256_768_22.c mpdecode_core.c phi0.c -o horus_l2 -Wall -DHORUS_L2_UNITTEST $ ./horus_l2 test 0: 22 bytes of payload data BER: 0.00 errors: 0 @@ -49,7 +49,7 @@ 5/ Unit testing interleaver: - $ gcc horus_l2.c golay23.c -o horus_l2 -Wall -DINTERLEAVER -DTEST_INTERLEAVER -DSCRAMBLER + $ gcc horus_l2.c golay23.c H_128_384_23.c H_256_768_22.c mpdecode_core.c phi0.c -o horus_l2 -Wall -DINTERLEAVER -DTEST_INTERLEAVER -DSCRAMBLER 6/ Compile for use as decoder called by fsk_horus.m and fsk_horus_stream.m: @@ -559,6 +559,7 @@ void interleave(unsigned char *inout, int nbytes, int dir) #ifdef TEST_INTERLEAVER int main(void) { int nbytes = 43; + //int nbytes = 63; // v2 large packet unsigned char inout[nbytes]; unsigned char inter[nbytes]; unsigned char incopy[nbytes]; @@ -747,6 +748,7 @@ int test_sending_bytes(int nbytes, float ber, int error_pattern) { /* unit test designed to run on a PC */ int main(void) { + printf("Horus v1 length packets (22 bytes)\n"); printf("test 0: BER: 0.00 ...........: %d\n", test_sending_bytes(22, 0.00, 0)); printf("test 1: BER: 0.01 ...........: %d\n", test_sending_bytes(22, 0.01, 0)); printf("test 2: BER: 0.05 ...........: %d\n", test_sending_bytes(22, 0.05, 0)); @@ -765,6 +767,46 @@ int main(void) { codeword after interleaving */ printf("test 5: 1 error every 12 bits: %d\n", test_sending_bytes(22, 0.00, 2)); + + printf("Horus v2 length packets (16 bytes)\n"); + printf("test 0: BER: 0.00 ...........: %d\n", test_sending_bytes(16, 0.00, 0)); + printf("test 1: BER: 0.01 ...........: %d\n", test_sending_bytes(16, 0.01, 0)); + printf("test 2: BER: 0.05 ...........: %d\n", test_sending_bytes(16, 0.05, 0)); + + /* we expect this always to fail, as chance of > 3 errors/codeword is high */ + + printf("test 3: BER: 0.10 ...........: %d\n", test_sending_bytes(16, 0.10, 0)); + + /* -DINTERLEAVER will make this puppy pass */ + + printf("test 4: 8 bit burst error....: %d\n", test_sending_bytes(16, 0.00, 1)); + + /* Insert 2 errors in every codeword, the maximum correction + capability of a Golay (23,12) code. note this one will fail + with -DINTERLEAVER, as we can't guarantee <= 3 errors per + codeword after interleaving */ + + printf("test 5: 1 error every 12 bits: %d\n", test_sending_bytes(16, 0.00, 2)); + + printf("Horus v2 length packets (32 bytes)\n"); + printf("test 0: BER: 0.00 ...........: %d\n", test_sending_bytes(32, 0.00, 0)); + printf("test 1: BER: 0.01 ...........: %d\n", test_sending_bytes(32, 0.01, 0)); + printf("test 2: BER: 0.05 ...........: %d\n", test_sending_bytes(32, 0.05, 0)); + + /* we expect this always to fail, as chance of > 3 errors/codeword is high */ + + printf("test 3: BER: 0.10 ...........: %d\n", test_sending_bytes(32, 0.10, 0)); + + /* -DINTERLEAVER will make this puppy pass */ + + printf("test 4: 8 bit burst error....: %d\n", test_sending_bytes(32, 0.00, 1)); + + /* Insert 2 errors in every codeword, the maximum correction + capability of a Golay (23,12) code. note this one will fail + with -DINTERLEAVER, as we can't guarantee <= 3 errors per + codeword after interleaving */ + + printf("test 5: 1 error every 12 bits: %d\n", test_sending_bytes(32, 0.00, 2)); return 0; } #endif diff --git a/src/run_fer_test.py b/src/run_fer_test.py index 10ac134..855f42e 100644 --- a/src/run_fer_test.py +++ b/src/run_fer_test.py @@ -82,17 +82,17 @@ MODE_TYPES = { 'binary': { 'id': 0, 'nfsk': 4, - 'bits_per_frame': 360 + 'bits_per_frame': 22*8 # UNCODED bits per frame. }, '128bit': { 'id': 1, 'nfsk': 2, # Convert back to 4FSK once 4FSK SD/LLRs are working. - 'bits_per_frame': 384 + 'bits_per_frame': 128 }, '256bit': { 'id': 1, 'nfsk': 2, # Convert back to 4FSK once 4FSK SD/LLRs are working. - 'bits_per_frame': 768 + 'bits_per_frame': 256 } }