kopia lustrzana https://github.com/projecthorus/horusdemodlib
				
				
				
			Initial LDPC encoding/decoding
							rodzic
							
								
									90cc397988
								
							
						
					
					
						commit
						a97f62da15
					
				| 
						 | 
				
			
			@ -6,6 +6,7 @@ set(horus_srcs
 | 
			
		|||
  kiss_fftr.c
 | 
			
		||||
  mpdecode_core.c
 | 
			
		||||
  H_256_768_22.c
 | 
			
		||||
  H_128_384_23.c
 | 
			
		||||
  golay23.c
 | 
			
		||||
  phi0.c
 | 
			
		||||
  horus_api.c
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,11 +6,15 @@
 | 
			
		|||
 | 
			
		||||
#define H_128_384_23_NUMBERPARITYBITS 256
 | 
			
		||||
#define H_128_384_23_MAX_ROW_WEIGHT 3
 | 
			
		||||
#define H_128_384_23_DATA_BYTES       16
 | 
			
		||||
#define H_128_384_23_PARITY_BYTES     32
 | 
			
		||||
#define H_128_384_23_BITS_PER_PACKET   ((H_128_384_23_DATA_BYTES + H_128_384_23_PARITY_BYTES) * 8)
 | 
			
		||||
#define H_128_384_23_CODELENGTH 384
 | 
			
		||||
#define H_128_384_23_NUMBERROWSHCOLS 128
 | 
			
		||||
#define H_128_384_23_MAX_COL_WEIGHT 5
 | 
			
		||||
#define H_128_384_23_DEC_TYPE 0
 | 
			
		||||
#define H_128_384_23_MAX_ITER 100
 | 
			
		||||
#define H_128_384_23_COPRIME 347
 | 
			
		||||
 | 
			
		||||
extern const uint16_t H_128_384_23_H_rows[];
 | 
			
		||||
extern const uint16_t H_128_384_23_H_cols[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,11 +6,15 @@
 | 
			
		|||
 | 
			
		||||
#define H_256_768_22_NUMBERPARITYBITS 512
 | 
			
		||||
#define H_256_768_22_MAX_ROW_WEIGHT 2
 | 
			
		||||
#define H_256_768_22_DATA_BYTES       32
 | 
			
		||||
#define H_256_768_22_PARITY_BYTES     64
 | 
			
		||||
#define H_256_768_22_BITS_PER_PACKET   ((H_256_768_22_DATA_BYTES + H_256_768_22_PARITY_BYTES) * 8)
 | 
			
		||||
#define H_256_768_22_CODELENGTH 768
 | 
			
		||||
#define H_256_768_22_NUMBERROWSHCOLS 256
 | 
			
		||||
#define H_256_768_22_MAX_COL_WEIGHT 4
 | 
			
		||||
#define H_256_768_22_DEC_TYPE 0
 | 
			
		||||
#define H_256_768_22_MAX_ITER 100
 | 
			
		||||
#define H_256_768_22_COPRIME 347
 | 
			
		||||
 | 
			
		||||
extern const uint16_t H_256_768_22_H_rows[];
 | 
			
		||||
extern const uint16_t H_256_768_22_H_cols[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								src/fsk.h
								
								
								
								
							
							
						
						
									
										18
									
								
								src/fsk.h
								
								
								
								
							| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
 | 
			
		||||
/* default internal parameters */
 | 
			
		||||
#define FSK_DEFAULT_P 8
 | 
			
		||||
#define FSK_DEFAULT_NSYM 50
 | 
			
		||||
#define FSK_DEFAULT_NSYM  50
 | 
			
		||||
 | 
			
		||||
struct FSK {
 | 
			
		||||
    /*  Static parameters set up by fsk_init */
 | 
			
		||||
| 
						 | 
				
			
			@ -188,10 +188,22 @@ void fsk_demod(struct FSK *fsk, uint8_t rx_bits[],COMP fsk_in[]);
 | 
			
		|||
 *  demodulated can be found by calling fsk_nin().
 | 
			
		||||
 * 
 | 
			
		||||
 * struct FSK *fsk - FSK config/state struct, set up by fsk_create
 | 
			
		||||
 * float rx_bits[] - Buffer for Nbits soft decision bits to be written
 | 
			
		||||
 * float rx_sd[] - Buffer for Nbits soft decision bits to be written
 | 
			
		||||
 * float fsk_in[] - nin samples of modualted FSK
 | 
			
		||||
 */
 | 
			
		||||
void fsk_demod_sd(struct FSK *fsk, float rx_bits[],COMP fsk_in[]);
 | 
			
		||||
void fsk_demod_sd(struct FSK *fsk, float rx_sd[], COMP fsk_in[]);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * " Why not both? "
 | 
			
		||||
 * Demodulate some number of FSK samples. The number of samples to be 
 | 
			
		||||
 *  demodulated can be found by calling fsk_nin().
 | 
			
		||||
 * 
 | 
			
		||||
 * struct FSK *fsk - FSK config/state struct, set up by fsk_create
 | 
			
		||||
 * float rx_bits[] - Buffer for Nbits soft decision bits to be written
 | 
			
		||||
 * float rx_sd[] - Buffer for Nbits soft decision bits to be written
 | 
			
		||||
 * float fsk_in[] - nin samples of modualted FSK
 | 
			
		||||
 */
 | 
			
		||||
void fsk_demod_core(struct FSK *fsk, uint8_t rx_bits[], float rx_sd[], COMP fsk_in[]);
 | 
			
		||||
 | 
			
		||||
/* enables/disables normalisation of eye diagram samples */
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										180
									
								
								src/horus_api.c
								
								
								
								
							
							
						
						
									
										180
									
								
								src/horus_api.c
								
								
								
								
							| 
						 | 
				
			
			@ -52,6 +52,7 @@ struct horus {
 | 
			
		|||
    int         uw_len;              /* length of unique word               */
 | 
			
		||||
    int         max_packet_len;      /* max length of a telemetry packet    */
 | 
			
		||||
    uint8_t    *rx_bits;             /* buffer of received bits             */
 | 
			
		||||
    float      *soft_bits;           /* buffer of soft decision outputs     */
 | 
			
		||||
    int         rx_bits_len;         /* length of rx_bits buffer            */
 | 
			
		||||
    int         crc_ok;              /* most recent packet checksum results */
 | 
			
		||||
    int         total_payload_bits;  /* num bits rx-ed in last RTTY packet  */
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +61,7 @@ struct horus {
 | 
			
		|||
/* Unique word for Horus RTTY 7 bit '$' character, 3 sync bits,
 | 
			
		||||
   repeated 5 times */
 | 
			
		||||
 | 
			
		||||
int8_t uw_horus_rtty[] = {
 | 
			
		||||
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,
 | 
			
		||||
| 
						 | 
				
			
			@ -86,12 +87,13 @@ int8_t uw_horus_binary_v2[] = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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){
 | 
			
		||||
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));
 | 
			
		||||
 | 
			
		||||
    if (mode == HORUS_MODE_RTTY_7N2){
 | 
			
		||||
        // RTTY Mode defaults - 100 baud, no assumptions about tone spacing.
 | 
			
		||||
        return horus_open_advanced(HORUS_MODE_RTTY, HORUS_RTTY_DEFAULT_BAUD, -1);
 | 
			
		||||
        return horus_open_advanced(HORUS_MODE_RTTY_7N2, 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -102,14 +104,14 @@ struct horus *horus_open (int mode) {
 | 
			
		|||
 | 
			
		||||
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));
 | 
			
		||||
    assert((mode == HORUS_MODE_RTTY_7N2) || (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) {
 | 
			
		||||
    if (mode == HORUS_MODE_RTTY_7N2) {
 | 
			
		||||
        // Parameter setup for RTTY Reception
 | 
			
		||||
 | 
			
		||||
        hstates->mFSK = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -130,11 +132,11 @@ struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing) {
 | 
			
		|||
 | 
			
		||||
        /* map UW to make it easier to search for */
 | 
			
		||||
 | 
			
		||||
        for (i=0; i<sizeof(uw_horus_rtty); i++) {
 | 
			
		||||
            hstates->uw[i] = 2*uw_horus_rtty[i] - 1;
 | 
			
		||||
        for (i=0; i<sizeof(uw_horus_rtty_7N2); i++) {
 | 
			
		||||
            hstates->uw[i] = 2*uw_horus_rtty_7N2[i] - 1;
 | 
			
		||||
        }        
 | 
			
		||||
        hstates->uw_len = sizeof(uw_horus_rtty);
 | 
			
		||||
        hstates->uw_thresh = sizeof(uw_horus_rtty) - 2;  /* allow a few bit errors in UW detection */
 | 
			
		||||
        hstates->uw_len = sizeof(uw_horus_rtty_7N2);
 | 
			
		||||
        hstates->uw_thresh = sizeof(uw_horus_rtty_7N2) - 2;  /* allow a few bit errors in UW detection */
 | 
			
		||||
        hstates->rx_bits_len = hstates->max_packet_len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +168,66 @@ struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing) {
 | 
			
		|||
        horus_l2_init();
 | 
			
		||||
        hstates->rx_bits_len = hstates->max_packet_len;
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: Horus 256/128-bit modes here.
 | 
			
		||||
 | 
			
		||||
    if (mode == HORUS_MODE_BINARY_V2_256BIT) {
 | 
			
		||||
        // Parameter setup for the Legacy Horus Binary Mode (22 byte frames, Golay encoding)
 | 
			
		||||
 | 
			
		||||
        hstates->mFSK = 4;
 | 
			
		||||
        hstates->max_packet_len = HORUS_BINARY_V2_256BIT_NUM_CODED_BITS ;
 | 
			
		||||
 | 
			
		||||
        // If baud rate not provided, use default
 | 
			
		||||
        if (hstates->Rs == -1){
 | 
			
		||||
            hstates->Rs = HORUS_BINARY_V2_256BIT_DEFAULT_BAUD;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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_V2_256BIT_DEFAULT_TONE_SPACING;
 | 
			
		||||
            mask = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Tone spacing provided, enable mask estimation.
 | 
			
		||||
            mask = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i=0; i<sizeof(uw_horus_binary_v2); i++) {
 | 
			
		||||
            hstates->uw[i] = 2*uw_horus_binary_v2[i] - 1;
 | 
			
		||||
        }
 | 
			
		||||
        hstates->uw_len = sizeof(uw_horus_binary_v2);
 | 
			
		||||
        hstates->uw_thresh = sizeof(uw_horus_binary_v2) - 2; /* allow a few bit errors in UW detection */
 | 
			
		||||
        // TODO: Any initialization required?
 | 
			
		||||
        // horus_l2_init();
 | 
			
		||||
        hstates->rx_bits_len = hstates->max_packet_len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mode == HORUS_MODE_BINARY_V2_128BIT) {
 | 
			
		||||
        // Parameter setup for the Legacy Horus Binary Mode (22 byte frames, Golay encoding)
 | 
			
		||||
 | 
			
		||||
        hstates->mFSK = 4;
 | 
			
		||||
        hstates->max_packet_len = HORUS_BINARY_V2_128BIT_NUM_CODED_BITS ;
 | 
			
		||||
 | 
			
		||||
        // If baud rate not provided, use default
 | 
			
		||||
        if (hstates->Rs == -1){
 | 
			
		||||
            hstates->Rs = HORUS_BINARY_V2_128BIT_DEFAULT_BAUD;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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_V2_128BIT_DEFAULT_TONE_SPACING;
 | 
			
		||||
            mask = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Tone spacing provided, enable mask estimation.
 | 
			
		||||
            mask = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i=0; i<sizeof(uw_horus_binary_v2); i++) {
 | 
			
		||||
            hstates->uw[i] = 2*uw_horus_binary_v2[i] - 1;
 | 
			
		||||
        }
 | 
			
		||||
        hstates->uw_len = sizeof(uw_horus_binary_v2);
 | 
			
		||||
        hstates->uw_thresh = sizeof(uw_horus_binary_v2) - 2; /* allow a few bit errors in UW detection */
 | 
			
		||||
        // TODO: Any initialization required?
 | 
			
		||||
        // horus_l2_init();
 | 
			
		||||
        hstates->rx_bits_len = hstates->max_packet_len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create the FSK modedm struct. Note that the low-tone-frequency parameter is unused.
 | 
			
		||||
    #define UNUSED 1000
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +246,13 @@ struct horus *horus_open_advanced (int mode, int Rs, int tx_tone_spacing) {
 | 
			
		|||
        hstates->rx_bits[i] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // and the same for soft-bits
 | 
			
		||||
    hstates->soft_bits = (float*)malloc(sizeof(float) * hstates->rx_bits_len);
 | 
			
		||||
    assert(hstates->soft_bits != NULL);
 | 
			
		||||
    for(i=0; i<hstates->rx_bits_len; i++) {
 | 
			
		||||
        hstates->soft_bits[i] = 0.0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hstates->crc_ok = 0;
 | 
			
		||||
    hstates->total_payload_bits = 0;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -412,6 +480,83 @@ int extract_horus_binary_v1(struct horus *hstates, char hex_out[], int uw_loc) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int extract_horus_binary_v2_128(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  */
 | 
			
		||||
 | 
			
		||||
    int      j, b, nout;
 | 
			
		||||
    uint8_t  rxpacket[hstates->max_packet_len];
 | 
			
		||||
    uint8_t  rxbyte, *pout;
 | 
			
		||||
 
 | 
			
		||||
    /* convert bits to a packet of bytes */
 | 
			
		||||
    
 | 
			
		||||
    pout = rxpacket; nout = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (b=st; b<en; b+=nfield) {
 | 
			
		||||
 | 
			
		||||
        /* assemble bytes MSB to LSB */
 | 
			
		||||
 | 
			
		||||
        rxbyte = 0;
 | 
			
		||||
        for(j=0; j<nfield; j++) {
 | 
			
		||||
            assert(hstates->rx_bits[b+j] <= 1);
 | 
			
		||||
            rxbyte <<= 1;
 | 
			
		||||
            rxbyte |= hstates->rx_bits[b+j];
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /* build up output array */
 | 
			
		||||
        
 | 
			
		||||
        *pout++ = rxbyte;
 | 
			
		||||
        nout++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (hstates->verbose) {
 | 
			
		||||
        fprintf(stderr, "  extract_horus_binary_v2_128 nout: %d\n  Received Packet before decoding:\n  ", nout);
 | 
			
		||||
        for (b=0; b<nout; b++) {
 | 
			
		||||
            fprintf(stderr, "%02X", rxpacket[b]);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, "\n");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    uint8_t payload_bytes[HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES];
 | 
			
		||||
    float *softbits = hstates->soft_bits + uw_loc + sizeof(uw_horus_binary_v2);
 | 
			
		||||
    horus_ldpc_decode( payload_bytes, softbits , HORUS_MODE_BINARY_V2_128BIT);
 | 
			
		||||
 | 
			
		||||
    uint16_t crc_tx, crc_rx;
 | 
			
		||||
    crc_rx = horus_l2_gen_crc16(payload_bytes, HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES-2);
 | 
			
		||||
    crc_tx = (uint16_t)payload_bytes[HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES-2] +
 | 
			
		||||
        ((uint16_t)payload_bytes[HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES-1]<<8);
 | 
			
		||||
    
 | 
			
		||||
    if (hstates->verbose) {
 | 
			
		||||
        fprintf(stderr, "  extract_horus_binary_v2_128 crc_tx: %04X crc_rx: %04X\n", crc_tx, crc_rx);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* convert to ASCII string of hex characters */
 | 
			
		||||
 | 
			
		||||
    hex_out[0] = 0;
 | 
			
		||||
    char hex[3];
 | 
			
		||||
    for (b=0; b<HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES; b++) {
 | 
			
		||||
        sprintf(hex, "%02X", payload_bytes[b]);
 | 
			
		||||
        strcat(hex_out, hex);
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    if (hstates->verbose) {
 | 
			
		||||
        fprintf(stderr, "  nout: %d Decoded Payload bytes:\n  %s\n", nout, hex_out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* With noise input to FSK demod we can get occasinal UW matches,
 | 
			
		||||
       so a good idea to only pass on any packets that pass CRC */
 | 
			
		||||
    
 | 
			
		||||
    hstates->crc_ok = (crc_tx == crc_rx);
 | 
			
		||||
    if ( hstates->crc_ok) {
 | 
			
		||||
        hstates->total_payload_bits += HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return hstates->crc_ok;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quadrature) {
 | 
			
		||||
    int i, j, uw_loc, packet_detected;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +575,7 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad
 | 
			
		|||
 | 
			
		||||
    for(i=0,j=Nbits; j<rx_bits_len; i++,j++) {
 | 
			
		||||
        hstates->rx_bits[i] = hstates->rx_bits[j];
 | 
			
		||||
        hstates->soft_bits[i] = hstates->soft_bits[j];
 | 
			
		||||
    }
 | 
			
		||||
                   
 | 
			
		||||
    /* demodulate latest bits */
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +594,8 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad
 | 
			
		|||
            demod_in_comp[i].imag = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fsk_demod(hstates->fsk, &hstates->rx_bits[rx_bits_len-Nbits], demod_in_comp);
 | 
			
		||||
 | 
			
		||||
    fsk_demod_core(hstates->fsk, &hstates->rx_bits[rx_bits_len-Nbits], &hstates->soft_bits[rx_bits_len-Nbits], demod_in_comp);
 | 
			
		||||
    free(demod_in_comp);
 | 
			
		||||
    
 | 
			
		||||
    /* UW search to see if we can find the start of a packet in the buffer */
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +609,7 @@ 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) {
 | 
			
		||||
        if (hstates->mode == HORUS_MODE_RTTY_7N2) {
 | 
			
		||||
            packet_detected = extract_horus_rtty(hstates, ascii_out, uw_loc);
 | 
			
		||||
        }
 | 
			
		||||
        if (hstates->mode == HORUS_MODE_BINARY_V1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -477,6 +624,9 @@ int horus_rx(struct horus *hstates, char ascii_out[], short demod_in[], int quad
 | 
			
		|||
            exit(0);
 | 
			
		||||
            #endif
 | 
			
		||||
        }
 | 
			
		||||
        if (hstates->mode == HORUS_MODE_BINARY_V2_128BIT){
 | 
			
		||||
            packet_detected = extract_horus_binary_v2_128(hstates, ascii_out, uw_loc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return packet_detected;
 | 
			
		||||
| 
						 | 
				
			
			@ -508,7 +658,7 @@ 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) {
 | 
			
		||||
    if (hstates->mode == HORUS_MODE_RTTY_7N2) {
 | 
			
		||||
        return hstates->max_packet_len/10;     /* 7 bit ASCII, plus 3 sync bits */
 | 
			
		||||
    }
 | 
			
		||||
    if (hstates->mode == HORUS_MODE_BINARY_V1) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,8 @@
 | 
			
		|||
#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
 | 
			
		||||
#define HORUS_MODE_RTTY_7N2             90 // RTTY Decoding - 7N2
 | 
			
		||||
#define HORUS_MODE_RTTY_8N2             90 // RTTY Decoding - 8N2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Settings for Legacy Horus Binary Mode (Golay Encoding)
 | 
			
		||||
| 
						 | 
				
			
			@ -52,15 +53,15 @@
 | 
			
		|||
                                                        // 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_CODED_BITS               (768+32)
 | 
			
		||||
#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_CODED_BITS                  (384+32)
 | 
			
		||||
#define HORUS_BINARY_V2_128BIT_NUM_UNCODED_PAYLOAD_BYTES       16
 | 
			
		||||
#define HORUS_BINARY_V2_128BIT_DEFAULT_BAUD                    25
 | 
			
		||||
#define HORUS_BINARY_V2_128BIT_DEFAULT_BAUD                    100
 | 
			
		||||
#define HORUS_BINARY_V2_128BIT_DEFAULT_TONE_SPACING            270 
 | 
			
		||||
 | 
			
		||||
// Settings for RTTY Decoder
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,18 +82,17 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        switch(o) {
 | 
			
		||||
            case 'm':
 | 
			
		||||
                if ((strcmp(optarg, "RTTY") == 0) || (strcmp(optarg, "rtty") == 0)) {
 | 
			
		||||
                    mode = HORUS_MODE_RTTY;
 | 
			
		||||
                    mode = HORUS_MODE_RTTY_7N2;
 | 
			
		||||
                }
 | 
			
		||||
                if ((strcmp(optarg, "BINARY") == 0) || (strcmp(optarg, "binary") == 0)) {
 | 
			
		||||
                    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 ((strcmp(optarg, "256BIT") == 0) || (strcmp(optarg, "256bit") == 0)) {
 | 
			
		||||
                    mode = HORUS_MODE_BINARY_V2_256BIT;
 | 
			
		||||
                }
 | 
			
		||||
                if ((strcmp(optarg, "128BIT") == 0) || (strcmp(optarg, "128bit") == 0)) {
 | 
			
		||||
                    mode = HORUS_MODE_BINARY_V2_128BIT;
 | 
			
		||||
                }
 | 
			
		||||
                if (mode == -1) {
 | 
			
		||||
                    fprintf(stderr, "use --mode RTTY or --mode binary\n");
 | 
			
		||||
                    exit(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -228,6 +227,7 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        if (verbose) {
 | 
			
		||||
            fprintf(stderr, "read nin %d\n", horus_nin(hstates));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (horus_rx(hstates, ascii_out, demod_in, quadrature)) {
 | 
			
		||||
            fprintf(stdout, "%s", ascii_out);
 | 
			
		||||
            if (crc_results) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										379
									
								
								src/horus_l2.c
								
								
								
								
							
							
						
						
									
										379
									
								
								src/horus_l2.c
								
								
								
								
							| 
						 | 
				
			
			@ -59,14 +59,18 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "mpdecode_core.h"
 | 
			
		||||
#include "horus_l2.h"
 | 
			
		||||
#include "golay23.h"
 | 
			
		||||
#include "H_128_384_23.h"
 | 
			
		||||
#include "H_256_768_22.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HORUS_L2_UNITTEST
 | 
			
		||||
#define HORUS_L2_RX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static char uw[] = {'$','$'};
 | 
			
		||||
static const char uw[] = {'$','$'}; // UW for Horus Binary v1
 | 
			
		||||
static const char uw_v2[] =  {0x96, 0x69, 0x69, 0x96}; // UW for Horus Binary v2 modes
 | 
			
		||||
 | 
			
		||||
/* Function Prototypes ------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -780,6 +784,43 @@ struct TBinaryPacket
 | 
			
		|||
    uint16_t    Checksum;    // CRC16-CCITT Checksum.
 | 
			
		||||
}  __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct V2SmallBinaryPacket
 | 
			
		||||
{
 | 
			
		||||
// 4 byte preamble for high error rates ("0x96696996")
 | 
			
		||||
//	- to improve soft bit prediction
 | 
			
		||||
uint8_t   PayloadID;	// Legacy list
 | 
			
		||||
uint8_t   Counter;	// 8 bit counter
 | 
			
		||||
uint16_t  BiSeconds;	// Time of day / 2
 | 
			
		||||
uint8_t   Latitude[3];	// (int)(float * 1.0e7) / (1<<8)
 | 
			
		||||
uint8_t   Longitude[3];	// ( better than 10m precision )
 | 
			
		||||
uint16_t  Altitude;	// 0 - 65 km
 | 
			
		||||
uint8_t   Voltage;	// scaled 5.0v in 255 range
 | 
			
		||||
uint8_t   User;		// Temp / Sats
 | 
			
		||||
	// Temperature	6 bits MSB => (+30 to -32)
 | 
			
		||||
	// Satellites	2 bits LSB => 0,4,8,12 is good enough
 | 
			
		||||
uint16_t  Checksum;	// CRC16-CCITT Checksum.
 | 
			
		||||
}  __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct V2LargeBinaryPacket
 | 
			
		||||
{
 | 
			
		||||
    uint16_t     PayloadID;
 | 
			
		||||
    uint16_t	Counter;
 | 
			
		||||
    uint8_t	Hours;
 | 
			
		||||
    uint8_t	Minutes;
 | 
			
		||||
    uint8_t	Seconds;
 | 
			
		||||
    float	Latitude;
 | 
			
		||||
    float	Longitude;
 | 
			
		||||
    uint16_t  	Altitude;
 | 
			
		||||
    uint8_t     Speed;       // Speed in Knots (1-255 knots)
 | 
			
		||||
    uint8_t     Sats;
 | 
			
		||||
    int8_t      Temp;        // Twos Complement Temp value.
 | 
			
		||||
    uint8_t     BattVoltage; // 0 = 0.5v, 255 = 2.0V, linear steps in-between.
 | 
			
		||||
    uint8_t     User[9];
 | 
			
		||||
    uint16_t    Checksum;    // CRC16-CCITT Checksum.
 | 
			
		||||
}  __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
#ifdef GEN_TX_BITS
 | 
			
		||||
/* generate a file of tx_bits to modulate using fsk_horus.m for modem simulations */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -888,42 +929,103 @@ int main(void) {
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef GEN_TX_BITSTREAM
 | 
			
		||||
/* Generate a stream of encoded Horus packets in a format suitable to feed into fsk_mod */
 | 
			
		||||
 | 
			
		||||
int main(int argc,char *argv[]) {
 | 
			
		||||
    int nbytes = sizeof(struct TBinaryPacket);
 | 
			
		||||
    struct TBinaryPacket input_payload;
 | 
			
		||||
    int num_tx_data_bytes = horus_l2_get_num_tx_data_bytes(nbytes);
 | 
			
		||||
    unsigned char tx[num_tx_data_bytes];
 | 
			
		||||
    int i, framecnt;
 | 
			
		||||
 | 
			
		||||
    if(argc != 2){
 | 
			
		||||
        fprintf(stderr,"usage: %s numFrames\n",argv[0]);
 | 
			
		||||
    int i, framecnt, mode;
 | 
			
		||||
    int num_tx_data_bytes = 0;
 | 
			
		||||
 | 
			
		||||
    if(argc != 3){
 | 
			
		||||
        fprintf(stderr,"usage: %s numFrames mode\n",argv[0]);
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    framecnt = atoi(argv[1]);
 | 
			
		||||
    mode = atoi(argv[2]);
 | 
			
		||||
 | 
			
		||||
    /* all zeros is nastiest sequence for demod before scrambling */
 | 
			
		||||
 | 
			
		||||
    memset(&input_payload, 0, nbytes);
 | 
			
		||||
    input_payload.Checksum = horus_l2_gen_crc16((unsigned char*)&input_payload, nbytes-2);
 | 
			
		||||
    if (mode == 0){
 | 
			
		||||
        // Horus Mode v1
 | 
			
		||||
        int nbytes = sizeof(struct TBinaryPacket);
 | 
			
		||||
        struct TBinaryPacket input_payload;
 | 
			
		||||
        int num_tx_data_bytes = horus_l2_get_num_tx_data_bytes(nbytes);
 | 
			
		||||
        unsigned char tx[num_tx_data_bytes];
 | 
			
		||||
 | 
			
		||||
    horus_l2_encode_tx_packet(tx, (unsigned char*)&input_payload, nbytes);
 | 
			
		||||
        memset(&input_payload, 0, nbytes);
 | 
			
		||||
        input_payload.Checksum = horus_l2_gen_crc16((unsigned char*)&input_payload, nbytes-2);
 | 
			
		||||
 | 
			
		||||
    int b;
 | 
			
		||||
    uint8_t tx_bit;
 | 
			
		||||
    while(framecnt >= 0){
 | 
			
		||||
        for(i=0; i<num_tx_data_bytes; i++) {
 | 
			
		||||
            for(b=0; b<8; b++) {
 | 
			
		||||
                tx_bit = (tx[i] >> (7-b)) & 0x1; /* msb first */
 | 
			
		||||
                fwrite(&tx_bit,sizeof(uint8_t),1,stdout);
 | 
			
		||||
                fflush(stdout);
 | 
			
		||||
        horus_l2_encode_tx_packet(tx, (unsigned char*)&input_payload, nbytes);
 | 
			
		||||
 | 
			
		||||
        int b;
 | 
			
		||||
        uint8_t tx_bit;
 | 
			
		||||
        while(framecnt >= 0){
 | 
			
		||||
            for(i=0; i<num_tx_data_bytes; i++) {
 | 
			
		||||
                for(b=0; b<8; b++) {
 | 
			
		||||
                    tx_bit = (tx[i] >> (7-b)) & 0x1; /* msb first */
 | 
			
		||||
                    fwrite(&tx_bit,sizeof(uint8_t),1,stdout);
 | 
			
		||||
                    fflush(stdout);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            framecnt -= 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else if (mode == 1) {
 | 
			
		||||
        // 32-byte horus mode
 | 
			
		||||
        int nbytes = sizeof(struct V2LargeBinaryPacket);
 | 
			
		||||
        struct V2LargeBinaryPacket input_payload;
 | 
			
		||||
 | 
			
		||||
        int num_tx_data_bytes = sizeof(uw_v2) + H_256_768_22_DATA_BYTES + H_256_768_22_PARITY_BYTES;
 | 
			
		||||
        unsigned char tx[num_tx_data_bytes];
 | 
			
		||||
        memset(&input_payload, 0, nbytes);
 | 
			
		||||
 | 
			
		||||
        input_payload.PayloadID = 1;
 | 
			
		||||
        input_payload.Counter = 2;
 | 
			
		||||
        input_payload.Checksum = horus_l2_gen_crc16((unsigned char*)&input_payload, nbytes-2);
 | 
			
		||||
 | 
			
		||||
        int ldpc_tx_bytes = ldpc_encode_packet(tx, (unsigned char*)&input_payload, 2);
 | 
			
		||||
 | 
			
		||||
        int b;
 | 
			
		||||
        uint8_t tx_bit;
 | 
			
		||||
        while(framecnt >= 0){
 | 
			
		||||
            for(i=0; i<num_tx_data_bytes; i++) {
 | 
			
		||||
                for(b=0; b<8; b++) {
 | 
			
		||||
                    tx_bit = (tx[i] >> (7-b)) & 0x1; /* msb first */
 | 
			
		||||
                    fwrite(&tx_bit,sizeof(uint8_t),1,stdout);
 | 
			
		||||
                    fflush(stdout);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            framecnt -= 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else if (mode == 2) {
 | 
			
		||||
        // 16-byte horus mode
 | 
			
		||||
        int nbytes = sizeof(struct V2SmallBinaryPacket);
 | 
			
		||||
        struct V2SmallBinaryPacket input_payload;
 | 
			
		||||
 | 
			
		||||
        int num_tx_data_bytes = sizeof(uw_v2) + H_128_384_23_DATA_BYTES + H_128_384_23_PARITY_BYTES;
 | 
			
		||||
        unsigned char tx[num_tx_data_bytes];
 | 
			
		||||
        memset(&input_payload, 0, nbytes);
 | 
			
		||||
        input_payload.PayloadID = 1;
 | 
			
		||||
        input_payload.Counter = 2;
 | 
			
		||||
 | 
			
		||||
        input_payload.Checksum = horus_l2_gen_crc16((unsigned char*)&input_payload, nbytes-2);
 | 
			
		||||
 | 
			
		||||
        int ldpc_tx_bytes = ldpc_encode_packet(tx, (unsigned char*)&input_payload, 2);
 | 
			
		||||
 | 
			
		||||
        int b;
 | 
			
		||||
        uint8_t tx_bit;
 | 
			
		||||
        while(framecnt >= 0){
 | 
			
		||||
            for(i=0; i<num_tx_data_bytes; i++) {
 | 
			
		||||
                for(b=0; b<8; b++) {
 | 
			
		||||
                    tx_bit = (tx[i] >> (7-b)) & 0x1; /* msb first */
 | 
			
		||||
                    fwrite(&tx_bit,sizeof(uint8_t),1,stdout);
 | 
			
		||||
                    fflush(stdout);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            framecnt -= 1;
 | 
			
		||||
        }
 | 
			
		||||
        framecnt -= 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -944,3 +1046,236 @@ unsigned short horus_l2_gen_crc16(unsigned char* data_p, unsigned char length) {
 | 
			
		|||
    return crc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//  Take payload data bytes, prepend a unique word and append parity bits
 | 
			
		||||
int ldpc_encode_packet(unsigned char *out_data, unsigned char *in_data, int mode) {
 | 
			
		||||
    unsigned int   i, last = 0;
 | 
			
		||||
    unsigned char *pout;
 | 
			
		||||
 | 
			
		||||
    unsigned int data_bytes, parity_bytes, number_parity_bits, max_row_weight;
 | 
			
		||||
 | 
			
		||||
    if (mode == 1){
 | 
			
		||||
        // 32-byte Mode.
 | 
			
		||||
        data_bytes = H_256_768_22_DATA_BYTES;
 | 
			
		||||
        parity_bytes = H_256_768_22_PARITY_BYTES;
 | 
			
		||||
        number_parity_bits = H_256_768_22_NUMBERPARITYBITS;
 | 
			
		||||
        max_row_weight = H_256_768_22_MAX_ROW_WEIGHT;
 | 
			
		||||
    } else {
 | 
			
		||||
        // 16-byte Mode.
 | 
			
		||||
        data_bytes = H_128_384_23_DATA_BYTES;
 | 
			
		||||
        parity_bytes = H_128_384_23_PARITY_BYTES;
 | 
			
		||||
        number_parity_bits = H_128_384_23_NUMBERPARITYBITS;
 | 
			
		||||
        max_row_weight = H_128_384_23_MAX_ROW_WEIGHT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pout = out_data;
 | 
			
		||||
    memcpy(pout, uw_v2, sizeof(uw_v2));
 | 
			
		||||
    pout += sizeof(uw_v2);
 | 
			
		||||
    memcpy(pout, in_data, data_bytes);
 | 
			
		||||
    pout += data_bytes;
 | 
			
		||||
    memset(pout, 0, parity_bytes);
 | 
			
		||||
 | 
			
		||||
    // process parity bit offsets
 | 
			
		||||
    for (i = 0; i < number_parity_bits; i++) {
 | 
			
		||||
        unsigned int shift, j;
 | 
			
		||||
        uint8_t tmp;
 | 
			
		||||
 | 
			
		||||
	for(j = 0; j < max_row_weight; j++) {
 | 
			
		||||
        // This is a bit silly, move this out of this loop.
 | 
			
		||||
        if (mode  == 1){
 | 
			
		||||
            uint8_t tmp  = H_256_768_22_H_rows[i + number_parity_bits * j];
 | 
			
		||||
        } else if (mode == 2) {
 | 
			
		||||
		    uint8_t tmp  = H_128_384_23_H_rows[i + number_parity_bits * j];
 | 
			
		||||
        }
 | 
			
		||||
		if (!tmp)
 | 
			
		||||
			continue;
 | 
			
		||||
		tmp--;
 | 
			
		||||
		shift = 7 - (tmp & 7); // MSB
 | 
			
		||||
		last ^= in_data[tmp >> 3] >> shift;
 | 
			
		||||
	}
 | 
			
		||||
	shift = 7 - (i & 7); // MSB
 | 
			
		||||
	pout[i >> 3] |= (last & 1) << shift;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pout = out_data + sizeof(uw_v2);
 | 
			
		||||
    interleave(pout, data_bytes + parity_bytes, 0);
 | 
			
		||||
    scramble(pout, data_bytes + parity_bytes);
 | 
			
		||||
 | 
			
		||||
    return data_bytes + parity_bytes + sizeof(uw_v2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Scramble and interleave are 8bit lsb, but bitstream is sent msb */
 | 
			
		||||
#define LSB2MSB(X) (X + 7 - 2 * (X & 7) )
 | 
			
		||||
 | 
			
		||||
/* Invert bits - ldpc expects negative floats for high hits */
 | 
			
		||||
void soft_unscramble(float *in, float* out, int nbits) {
 | 
			
		||||
	int i, ibit;
 | 
			
		||||
	uint16_t scrambler = 0x4a80;  /* init additive scrambler at start of every frame */
 | 
			
		||||
	uint16_t scrambler_out;
 | 
			
		||||
 | 
			
		||||
	for ( i = 0; i < nbits; i++ ) {
 | 
			
		||||
		scrambler_out = ( (scrambler >> 1) ^ scrambler) & 0x1;
 | 
			
		||||
 | 
			
		||||
		/* modify i-th bit by xor-ing with scrambler output sequence */
 | 
			
		||||
		ibit = LSB2MSB(i);
 | 
			
		||||
		if ( scrambler_out ) {
 | 
			
		||||
			out[ibit] = in[ibit];
 | 
			
		||||
		} else {
 | 
			
		||||
			out[ibit] = -in[ibit];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		scrambler >>= 1;
 | 
			
		||||
		scrambler |= scrambler_out << 14;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// soft bit deinterleave
 | 
			
		||||
void soft_deinterleave(float *in, float* out, int mode) {
 | 
			
		||||
	int n, i, j, bits_per_packet, coprime;
 | 
			
		||||
 | 
			
		||||
    if (mode == 1) {
 | 
			
		||||
        // 256_768
 | 
			
		||||
        bits_per_packet = H_256_768_22_BITS_PER_PACKET;
 | 
			
		||||
        coprime = H_256_768_22_COPRIME;
 | 
			
		||||
    } else {
 | 
			
		||||
        bits_per_packet = H_128_384_23_BITS_PER_PACKET;
 | 
			
		||||
        coprime = H_128_384_23_COPRIME;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	for ( n = 0; n < bits_per_packet; n++ ) {
 | 
			
		||||
		i = LSB2MSB(n);
 | 
			
		||||
		j = LSB2MSB( (coprime * n) % bits_per_packet);
 | 
			
		||||
		out[i] = in[j];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// // packed bit deinterleave - same as Golay version , but different Coprime
 | 
			
		||||
// void bitwise_deinterleave(uint8_t *inout, int nbytes)
 | 
			
		||||
// {
 | 
			
		||||
//     uint16_t nbits = (uint16_t)nbytes*8;
 | 
			
		||||
//     uint32_t i, j, ibit, ibyte, ishift, jbyte, jshift;
 | 
			
		||||
//     uint8_t out[nbytes];
 | 
			
		||||
 | 
			
		||||
//     memset(out, 0, nbytes);
 | 
			
		||||
//     for(j = 0; j < nbits; j++) {
 | 
			
		||||
//         i = (COPRIME * j) % nbits;
 | 
			
		||||
 | 
			
		||||
//         /* read bit i */
 | 
			
		||||
//         ibyte = i>>3;
 | 
			
		||||
//         ishift = i&7;
 | 
			
		||||
//         ibit = (inout[ibyte] >> ishift) & 0x1;
 | 
			
		||||
 | 
			
		||||
// 	/* write bit i to bit j position */
 | 
			
		||||
//         jbyte = j>>3;
 | 
			
		||||
//         jshift = j&7;
 | 
			
		||||
//         out[jbyte] |= ibit << jshift;
 | 
			
		||||
//     }
 | 
			
		||||
 
 | 
			
		||||
//     memcpy(inout, out, nbytes);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// /* Compare detected bits to corrected bits */
 | 
			
		||||
// void ldpc_errors( const uint8_t *outbytes, uint8_t *rx_bytes ) {
 | 
			
		||||
// 	int	length = DATA_BYTES + PARITY_BYTES;
 | 
			
		||||
// 	uint8_t temp[length];
 | 
			
		||||
// 	int	i, percentage, count = 0;
 | 
			
		||||
// 	memcpy(temp, rx_bytes, length);
 | 
			
		||||
 | 
			
		||||
// 	scramble(temp, length); // use scrambler from Golay code
 | 
			
		||||
// 	bitwise_deinterleave(temp, length);
 | 
			
		||||
 | 
			
		||||
// 	// count bits changed during error correction
 | 
			
		||||
// 	for(i = 0; i < BITS_PER_PACKET; i++) {
 | 
			
		||||
// 		int x, y, offset, shift;
 | 
			
		||||
 | 
			
		||||
// 		shift = i & 7;
 | 
			
		||||
// 		offset = i >> 3;
 | 
			
		||||
// 		x = temp[offset] >> shift;
 | 
			
		||||
// 		y = outbytes[offset] >> shift;
 | 
			
		||||
// 		count += (x ^ y) & 1;
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	// scale errors against a maximum of 20% BER
 | 
			
		||||
// 	percentage = (count * 5 * 100) / BITS_PER_PACKET;
 | 
			
		||||
// 	if (percentage > 100)
 | 
			
		||||
// 		percentage = 100;
 | 
			
		||||
// 	set_error_count( percentage );
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
/* LDPC decode */
 | 
			
		||||
void horus_ldpc_decode(uint8_t *payload, float *sd, int mode) {
 | 
			
		||||
	float sum, mean, sumsq, estEsN0, x;
 | 
			
		||||
    int bits_per_packet;
 | 
			
		||||
 | 
			
		||||
    if(mode == 1){
 | 
			
		||||
        bits_per_packet = H_256_768_22_BITS_PER_PACKET;
 | 
			
		||||
    } else {
 | 
			
		||||
        bits_per_packet = H_128_384_23_BITS_PER_PACKET;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float llr[bits_per_packet];
 | 
			
		||||
    float temp[bits_per_packet];
 | 
			
		||||
    uint8_t outbits[bits_per_packet];
 | 
			
		||||
 | 
			
		||||
	int b, i, parityCC;
 | 
			
		||||
	struct LDPC ldpc;
 | 
			
		||||
 | 
			
		||||
	/* normalise bitstream to log-like */
 | 
			
		||||
	sum = 0.0;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ )
 | 
			
		||||
		sum += fabs(sd[i]);
 | 
			
		||||
	mean = sum / bits_per_packet;
 | 
			
		||||
 | 
			
		||||
	sumsq = 0.0;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ ) {
 | 
			
		||||
		x = fabs(sd[i]) / mean - 1.0;
 | 
			
		||||
		sumsq += x * x;
 | 
			
		||||
	}
 | 
			
		||||
	estEsN0 =  2.0 * bits_per_packet / (sumsq + 1.0e-3) / mean;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ )
 | 
			
		||||
		llr[i] = estEsN0 * sd[i];
 | 
			
		||||
 | 
			
		||||
	/* reverse whitening and re-order bits */
 | 
			
		||||
	soft_unscramble(llr, temp, bits_per_packet);
 | 
			
		||||
	soft_deinterleave(temp, llr, mode);
 | 
			
		||||
 | 
			
		||||
	/* correct errors */
 | 
			
		||||
    if (mode == 1){
 | 
			
		||||
        // 32-byte mode H_256_768_22
 | 
			
		||||
        ldpc.max_iter = H_256_768_22_MAX_ITER;
 | 
			
		||||
        ldpc.dec_type = 0;
 | 
			
		||||
        ldpc.q_scale_factor = 1;
 | 
			
		||||
        ldpc.r_scale_factor = 1;
 | 
			
		||||
        ldpc.CodeLength = H_256_768_22_CODELENGTH;
 | 
			
		||||
        ldpc.NumberParityBits = H_256_768_22_NUMBERPARITYBITS;
 | 
			
		||||
        ldpc.NumberRowsHcols = H_256_768_22_NUMBERROWSHCOLS;
 | 
			
		||||
        ldpc.max_row_weight = H_256_768_22_MAX_ROW_WEIGHT;
 | 
			
		||||
        ldpc.max_col_weight = H_256_768_22_MAX_COL_WEIGHT;
 | 
			
		||||
        ldpc.H_rows = (uint16_t *)H_256_768_22_H_rows;
 | 
			
		||||
        ldpc.H_cols = (uint16_t *)H_256_768_22_H_cols;
 | 
			
		||||
    } else {
 | 
			
		||||
        // 16-byte mode
 | 
			
		||||
        ldpc.max_iter = H_128_384_23_MAX_ITER;
 | 
			
		||||
        ldpc.dec_type = 0;
 | 
			
		||||
        ldpc.q_scale_factor = 1;
 | 
			
		||||
        ldpc.r_scale_factor = 1;
 | 
			
		||||
        ldpc.CodeLength = H_128_384_23_CODELENGTH;
 | 
			
		||||
        ldpc.NumberParityBits = H_128_384_23_NUMBERPARITYBITS;
 | 
			
		||||
        ldpc.NumberRowsHcols = H_128_384_23_NUMBERROWSHCOLS;
 | 
			
		||||
        ldpc.max_row_weight = H_128_384_23_MAX_ROW_WEIGHT;
 | 
			
		||||
        ldpc.max_col_weight = H_128_384_23_MAX_COL_WEIGHT;
 | 
			
		||||
        ldpc.H_rows = (uint16_t *)H_128_384_23_H_rows;
 | 
			
		||||
        ldpc.H_cols = (uint16_t *)H_128_384_23_H_cols;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	i = run_ldpc_decoder(&ldpc, outbits, llr, &parityCC);
 | 
			
		||||
 | 
			
		||||
	/* convert MSB bits to a packet of bytes */    
 | 
			
		||||
	for (b = 0; b < (bits_per_packet/8); b++) {
 | 
			
		||||
		uint8_t rxbyte = 0;
 | 
			
		||||
		for(i=0; i<8; i++)
 | 
			
		||||
			rxbyte |= outbits[b*8+i] << (7 - i);
 | 
			
		||||
		payload[b] = rxbyte;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,4 +27,10 @@ void horus_l2_decode_rx_packet(unsigned char *output_payload_data,
 | 
			
		|||
 | 
			
		||||
unsigned short horus_l2_gen_crc16(unsigned char* data_p, unsigned char length);
 | 
			
		||||
 | 
			
		||||
int ldpc_encode_packet(uint8_t *buff_mfsk, uint8_t *FSK, int mode);
 | 
			
		||||
 | 
			
		||||
void soft_unscramble(float *in, float* out, int nbits);
 | 
			
		||||
void soft_deinterleave(float *in, float* out, int mode);
 | 
			
		||||
void horus_ldpc_decode(uint8_t *payload, float *sd, int mode);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,199 @@
 | 
			
		|||
/* ldpc interface to decoder
 | 
			
		||||
 *
 | 
			
		||||
 * 	It is expected that the switch to ldpc will give a 60% speed improvement
 | 
			
		||||
 * over golay code, with no loss of performance over white noise - the use of
 | 
			
		||||
 * soft-bit detection and longer codewords compensating for the expected 2dB loss
 | 
			
		||||
 * from reducing the number of parity bits.
 | 
			
		||||
 *
 | 
			
		||||
 * Golay code can reliably correct a 10% BER, equivalent to a 20% loss of signal
 | 
			
		||||
 * during deep fading. It is not clear how well ldpc will cope with deep fading,
 | 
			
		||||
 * but the shorter packers are bound to be more badly affected.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "math.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
#include "mpdecode_core.h"
 | 
			
		||||
#include "horus_l2.h"
 | 
			
		||||
#include "H_128_384_23.h"
 | 
			
		||||
#include "H_256_768_22.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define MAX_ITER         20
 | 
			
		||||
 | 
			
		||||
/* Scramble and interleave are 8bit lsb, but bitstream is sent msb */
 | 
			
		||||
#define LSB2MSB(X) (X + 7 - 2 * (X & 7) )
 | 
			
		||||
 | 
			
		||||
/* Invert bits - ldpc expects negative floats for high hits */
 | 
			
		||||
void soft_unscramble(float *in, float* out, int nbits) {
 | 
			
		||||
	int i, ibit;
 | 
			
		||||
	uint16_t scrambler = 0x4a80;  /* init additive scrambler at start of every frame */
 | 
			
		||||
	uint16_t scrambler_out;
 | 
			
		||||
 | 
			
		||||
	for ( i = 0; i < nbits; i++ ) {
 | 
			
		||||
		scrambler_out = ( (scrambler >> 1) ^ scrambler) & 0x1;
 | 
			
		||||
 | 
			
		||||
		/* modify i-th bit by xor-ing with scrambler output sequence */
 | 
			
		||||
		ibit = LSB2MSB(i);
 | 
			
		||||
		if ( scrambler_out ) {
 | 
			
		||||
			out[ibit] = in[ibit];
 | 
			
		||||
		} else {
 | 
			
		||||
			out[ibit] = -in[ibit];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		scrambler >>= 1;
 | 
			
		||||
		scrambler |= scrambler_out << 14;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// soft bit deinterleave
 | 
			
		||||
void soft_deinterleave(float *in, float* out, int mode) {
 | 
			
		||||
	int n, i, j, bits_per_packet, coprime;
 | 
			
		||||
 | 
			
		||||
    if (mode == 1) {
 | 
			
		||||
        // 256_768
 | 
			
		||||
        bits_per_packet = H_256_768_22_BITS_PER_PACKET;
 | 
			
		||||
        coprime = H_256_768_22_COPRIME;
 | 
			
		||||
    } else {
 | 
			
		||||
        bits_per_packet = H_128_384_23_BITS_PER_PACKET;
 | 
			
		||||
        coprime = H_128_384_23_COPRIME;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	for ( n = 0; n < bits_per_packet; n++ ) {
 | 
			
		||||
		i = LSB2MSB(n);
 | 
			
		||||
		j = LSB2MSB( (coprime * n) % bits_per_packet);
 | 
			
		||||
		out[i] = in[j];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// // packed bit deinterleave - same as Golay version , but different Coprime
 | 
			
		||||
// void bitwise_deinterleave(uint8_t *inout, int nbytes)
 | 
			
		||||
// {
 | 
			
		||||
//     uint16_t nbits = (uint16_t)nbytes*8;
 | 
			
		||||
//     uint32_t i, j, ibit, ibyte, ishift, jbyte, jshift;
 | 
			
		||||
//     uint8_t out[nbytes];
 | 
			
		||||
 | 
			
		||||
//     memset(out, 0, nbytes);
 | 
			
		||||
//     for(j = 0; j < nbits; j++) {
 | 
			
		||||
//         i = (COPRIME * j) % nbits;
 | 
			
		||||
 | 
			
		||||
//         /* read bit i */
 | 
			
		||||
//         ibyte = i>>3;
 | 
			
		||||
//         ishift = i&7;
 | 
			
		||||
//         ibit = (inout[ibyte] >> ishift) & 0x1;
 | 
			
		||||
 | 
			
		||||
// 	/* write bit i to bit j position */
 | 
			
		||||
//         jbyte = j>>3;
 | 
			
		||||
//         jshift = j&7;
 | 
			
		||||
//         out[jbyte] |= ibit << jshift;
 | 
			
		||||
//     }
 | 
			
		||||
 
 | 
			
		||||
//     memcpy(inout, out, nbytes);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// /* Compare detected bits to corrected bits */
 | 
			
		||||
// void ldpc_errors( const uint8_t *outbytes, uint8_t *rx_bytes ) {
 | 
			
		||||
// 	int	length = DATA_BYTES + PARITY_BYTES;
 | 
			
		||||
// 	uint8_t temp[length];
 | 
			
		||||
// 	int	i, percentage, count = 0;
 | 
			
		||||
// 	memcpy(temp, rx_bytes, length);
 | 
			
		||||
 | 
			
		||||
// 	scramble(temp, length); // use scrambler from Golay code
 | 
			
		||||
// 	bitwise_deinterleave(temp, length);
 | 
			
		||||
 | 
			
		||||
// 	// count bits changed during error correction
 | 
			
		||||
// 	for(i = 0; i < BITS_PER_PACKET; i++) {
 | 
			
		||||
// 		int x, y, offset, shift;
 | 
			
		||||
 | 
			
		||||
// 		shift = i & 7;
 | 
			
		||||
// 		offset = i >> 3;
 | 
			
		||||
// 		x = temp[offset] >> shift;
 | 
			
		||||
// 		y = outbytes[offset] >> shift;
 | 
			
		||||
// 		count += (x ^ y) & 1;
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	// scale errors against a maximum of 20% BER
 | 
			
		||||
// 	percentage = (count * 5 * 100) / BITS_PER_PACKET;
 | 
			
		||||
// 	if (percentage > 100)
 | 
			
		||||
// 		percentage = 100;
 | 
			
		||||
// 	set_error_count( percentage );
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
/* LDPC decode */
 | 
			
		||||
void horus_ldpc_decode(uint8_t *payload, float *sd, int mode) {
 | 
			
		||||
	float sum, mean, sumsq, estEsN0, x;
 | 
			
		||||
    int bits_per_packet;
 | 
			
		||||
 | 
			
		||||
    if(mode == 1){
 | 
			
		||||
        bits_per_packet = H_256_768_22_BITS_PER_PACKET;
 | 
			
		||||
    } else {
 | 
			
		||||
        bits_per_packet = H_128_384_23_BITS_PER_PACKET;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float llr[bits_per_packet];
 | 
			
		||||
    float temp[bits_per_packet];
 | 
			
		||||
    uint8_t outbits[bits_per_packet];
 | 
			
		||||
 | 
			
		||||
	int b, i, parityCC;
 | 
			
		||||
	struct LDPC ldpc;
 | 
			
		||||
 | 
			
		||||
	/* normalise bitstream to log-like */
 | 
			
		||||
	sum = 0.0;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ )
 | 
			
		||||
		sum += fabs(sd[i]);
 | 
			
		||||
	mean = sum / bits_per_packet;
 | 
			
		||||
 | 
			
		||||
	sumsq = 0.0;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ ) {
 | 
			
		||||
		x = fabs(sd[i]) / mean - 1.0;
 | 
			
		||||
		sumsq += x * x;
 | 
			
		||||
	}
 | 
			
		||||
	estEsN0 =  2.0 * bits_per_packet / (sumsq + 1.0e-3) / mean;
 | 
			
		||||
	for ( i = 0; i < bits_per_packet; i++ )
 | 
			
		||||
		llr[i] = estEsN0 * sd[i];
 | 
			
		||||
 | 
			
		||||
	/* reverse whitening and re-order bits */
 | 
			
		||||
	soft_unscramble(llr, temp, bits_per_packet);
 | 
			
		||||
	soft_deinterleave(temp, llr, mode);
 | 
			
		||||
 | 
			
		||||
	/* correct errors */
 | 
			
		||||
    if (mode == 1){
 | 
			
		||||
        // 32-byte mode H_256_768_22
 | 
			
		||||
        ldpc.max_iter = H_256_768_22_MAX_ITER;
 | 
			
		||||
        ldpc.dec_type = 0;
 | 
			
		||||
        ldpc.q_scale_factor = 1;
 | 
			
		||||
        ldpc.r_scale_factor = 1;
 | 
			
		||||
        ldpc.CodeLength = H_256_768_22_CODELENGTH;
 | 
			
		||||
        ldpc.NumberParityBits = H_256_768_22_NUMBERPARITYBITS;
 | 
			
		||||
        ldpc.NumberRowsHcols = H_256_768_22_NUMBERROWSHCOLS;
 | 
			
		||||
        ldpc.max_row_weight = H_256_768_22_MAX_ROW_WEIGHT;
 | 
			
		||||
        ldpc.max_col_weight = H_256_768_22_MAX_COL_WEIGHT;
 | 
			
		||||
        ldpc.H_rows = (uint16_t *)H_256_768_22_H_rows;
 | 
			
		||||
        ldpc.H_cols = (uint16_t *)H_256_768_22_H_cols;
 | 
			
		||||
    } else {
 | 
			
		||||
        // 16-byte mode
 | 
			
		||||
        ldpc.max_iter = H_128_384_23_MAX_ITER;
 | 
			
		||||
        ldpc.dec_type = 0;
 | 
			
		||||
        ldpc.q_scale_factor = 1;
 | 
			
		||||
        ldpc.r_scale_factor = 1;
 | 
			
		||||
        ldpc.CodeLength = H_128_384_23_CODELENGTH;
 | 
			
		||||
        ldpc.NumberParityBits = H_128_384_23_NUMBERPARITYBITS;
 | 
			
		||||
        ldpc.NumberRowsHcols = H_128_384_23_NUMBERROWSHCOLS;
 | 
			
		||||
        ldpc.max_row_weight = H_128_384_23_MAX_ROW_WEIGHT;
 | 
			
		||||
        ldpc.max_col_weight = H_128_384_23_MAX_COL_WEIGHT;
 | 
			
		||||
        ldpc.H_rows = (uint16_t *)H_128_384_23_H_rows;
 | 
			
		||||
        ldpc.H_cols = (uint16_t *)H_128_384_23_H_cols;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	i = run_ldpc_decoder(&ldpc, outbits, llr, &parityCC);
 | 
			
		||||
 | 
			
		||||
	/* convert MSB bits to a packet of bytes */    
 | 
			
		||||
	for (b = 0; b < (bits_per_packet/8); b++) {
 | 
			
		||||
		uint8_t rxbyte = 0;
 | 
			
		||||
		for(i=0; i<8; i++)
 | 
			
		||||
			rxbyte |= outbits[b*8+i] << (7 - i);
 | 
			
		||||
		payload[b] = rxbyte;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Ładowanie…
	
		Reference in New Issue