/* Soft-decision stack-based sequential decoder for K=32 r=1/2 convolutional code. This code implements the "stack-bucket" algorithm described in: "Fast Sequential Decoding Algorithm Using a Stack", F. Jelinek The ENCODE macro from Phil Karn's (KA9Q) Fano decoder is used. Written by Steve Franke, K9AN for WSJT-X (July 2015) */ #include "jelinek.h" #include #include #include #include /* memset */ #include "fano.h" /* WSPR uses the Layland-Lushbaugh code * Nonsystematic, non-quick look-in, dmin=?, dfree=? */ #define POLY1 0xf2d05351 #define POLY2 0xe4613c47 //Decoder - returns 0 on success, -1 on timeout int jelinek( unsigned int *metric, /* Final path metric (returned value) */ unsigned int *cycles, /* Cycle count (returned value) */ unsigned char *data, /* Decoded output data */ unsigned char *symbols, /* Raw deinterleaved input symbols */ unsigned int nbits, /* Number of output bits */ unsigned int stacksize, struct snode *stack, int mettab[2][256], /* Metric table, [sent sym][rx symbol] */ unsigned int maxcycles)/* Decoding timeout in cycles per bit */ { // Compute branch metrics for each symbol pair // The sequential decoding algorithm only uses the metrics, not the // symbol values. unsigned int i; long int metrics[81][4]; for(i=0; i>5)+200; //fast, but not particularly safe - totmet can be negative if( bucket > high_bucket ) high_bucket=bucket; if( bucket < low_bucket ) low_bucket=bucket; // place the 0 node on the stack, overwriting the parent (current) node stack[ptr].encstate=encstate; stack[ptr].gamma=totmet0; stack[ptr].depth=depth; stack[ptr].jpointer=buckets[bucket]; buckets[bucket]=ptr; // if in the tail, only need to evaluate the "0" branch. // Otherwise, enter this "if" and place the 1 node on the stack, if( depth <= nbits_minus_ntail ) { if( stackptr < stacksize_minus_1 ) { stackptr++; ptr=stackptr; } else { // stack full while( buckets[low_bucket] == 0 ) { //write latest to where the top of the lowest bucket points low_bucket++; } ptr=buckets[low_bucket]; buckets[low_bucket]=stack[ptr].jpointer; //make bucket point to next older entry } bucket=(totmet1>>5)+200; //this may not be safe on all compilers if( bucket > high_bucket ) high_bucket=bucket; if( bucket < low_bucket ) low_bucket=bucket; stack[ptr].encstate=encstate+1; stack[ptr].gamma=totmet1; stack[ptr].depth=depth; stack[ptr].jpointer=buckets[bucket]; buckets[bucket]=ptr; } // pick off the latest entry from the high bucket while( buckets[high_bucket] == 0 ) { high_bucket--; } ptr=buckets[high_bucket]; buckets[high_bucket]=stack[ptr].jpointer; depth=stack[ptr].depth; gamma=stack[ptr].gamma; encstate=stack[ptr].encstate; // we are done if the top entry on the stack is at depth nbits if (depth == nbits) { break; } } *cycles = i+1; *metric = gamma; /* Return final path metric */ // printf("cycles %d stackptr=%d, depth=%d, gamma=%d, encstate=%lx\n", // *cycles, stackptr, depth, *metric, encstate); for (i=0; i<7; i++) { data[i]=(encstate>>(48-i*8))&(0x00000000000000ff); } for (i=7; i<11; i++) { data[i]=0; } if(*cycles/nbits >= maxcycles) //timed out { return -1; } return 0; //success }