| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  This file is part of wsprd. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  File name: fano.c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Description: Soft decision Fano sequential decoder for K=32 r=1/2 | 
					
						
							|  |  |  |  convolutional code. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Copyright 1994, Phil Karn, KA9Q | 
					
						
							|  |  |  |  Minor modifications by Joe Taylor, K1JT | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  | #define LL 1  // Select Layland-Lushbaugh code
 | 
					
						
							| 
									
										
										
										
											2017-06-23 16:34:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2017-06-23 16:34:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  | #include "./fano.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct node { | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     unsigned long encstate;  // Encoder state of next node
 | 
					
						
							|  |  |  |     long gamma;              // Cumulative metric to this node
 | 
					
						
							|  |  |  |     int metrics[4];          // Metrics indexed by all possible tx syms
 | 
					
						
							|  |  |  |     int tm[2];               // Sorted metrics for current hypotheses
 | 
					
						
							|  |  |  |     int i;                   // Current branch being tested
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Convolutional coding polynomials. All are rate 1/2, K=32
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #ifdef NASA_STANDARD
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | /* "NASA standard" code by Massey & Costello
 | 
					
						
							|  |  |  |  * Nonsystematic, quick look-in, dmin=11, dfree=23 | 
					
						
							|  |  |  |  * used on Pioneer 10-12, Helios A,B | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #define POLY1 0xbbef6bb7
 | 
					
						
							|  |  |  | #define POLY2 0xbbef6bb5
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #ifdef MJ
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | /* Massey-Johannesson code
 | 
					
						
							|  |  |  |  * Nonsystematic, quick look-in, dmin=13, dfree>=23 | 
					
						
							|  |  |  |  * Purported to be more computationally efficient than Massey-Costello | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #define POLY1 0xb840a20f
 | 
					
						
							|  |  |  | #define POLY2 0xb840a20d
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #ifdef LL
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | /* Layland-Lushbaugh code
 | 
					
						
							|  |  |  |  * Nonsystematic, non-quick look-in, dmin=?, dfree=? | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | #define POLY1 0xf2d05351
 | 
					
						
							|  |  |  | #define POLY2 0xe4613c47
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convolutionally encode a packet. The input data bytes are read
 | 
					
						
							|  |  |  |  * high bit first and the encoded packet is written into 'symbols', | 
					
						
							|  |  |  |  * one symbol per byte. The first symbol is generated from POLY1, | 
					
						
							|  |  |  |  * the second from POLY2. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Storing only one symbol per byte uses more space, but it is faster | 
					
						
							|  |  |  |  * and easier than trying to pack them more compactly. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  | int encode(unsigned char *symbols,  // Output buffer, 2*8*nbytes
 | 
					
						
							|  |  |  |            unsigned char *data,     // Input buffer, nbytes
 | 
					
						
							|  |  |  |            unsigned int nbytes) {   // Number of bytes in data
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     unsigned long encstate; | 
					
						
							|  |  |  |     int sym; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     encstate = 0; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     while (nbytes-- != 0) { | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |         for (i = 7; i >= 0; i--) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             encstate = (encstate << 1) | ((*data >> i) & 1); | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |             ENCODE(sym, encstate); | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             *symbols++ = sym >> 1; | 
					
						
							|  |  |  |             *symbols++ = sym & 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         data++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Decode packet with the Fano algorithm.
 | 
					
						
							|  |  |  |  * Return 0 on success, -1 on timeout | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  | int fano(unsigned int *metric,      // Final path metric (returned value)
 | 
					
						
							|  |  |  |          unsigned int *cycles,      // Cycle count (returned value)
 | 
					
						
							|  |  |  |          unsigned int *maxnp,       // Progress before timeout (returned value)
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |          unsigned char *data,       // Decoded output data
 | 
					
						
							|  |  |  |          unsigned char *symbols,    // Raw deinterleaved input symbols
 | 
					
						
							|  |  |  |          unsigned int nbits,        // Number of output bits
 | 
					
						
							|  |  |  |          int mettab[2][256],        // Metric table, [sent sym][rx symbol]
 | 
					
						
							|  |  |  |          int delta,                 // Threshold adjust parameter
 | 
					
						
							|  |  |  |          unsigned int maxcycles) {  // Decoding timeout in cycles per bit
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     struct node *nodes;     // First node
 | 
					
						
							|  |  |  |     struct node *np;        // Current node
 | 
					
						
							|  |  |  |     struct node *lastnode;  // Last node
 | 
					
						
							|  |  |  |     struct node *tail;      // First node of tail
 | 
					
						
							|  |  |  |     int t;                  // Threshold
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     int m0, m1; | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     int ngamma; | 
					
						
							|  |  |  |     unsigned int lsym; | 
					
						
							|  |  |  |     unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     if ((nodes = (struct node *)malloc((nbits + 1) * sizeof(struct node))) == NULL) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         printf("malloc failed\n"); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     lastnode = &nodes[nbits - 1]; | 
					
						
							|  |  |  |     tail = &nodes[nbits - 31]; | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     *maxnp = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Compute all possible branch metrics for each symbol pair
 | 
					
						
							|  |  |  |      * This is the only place we actually look at the raw input symbols | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     for (np = nodes; np <= lastnode; np++) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         np->metrics[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]]; | 
					
						
							|  |  |  |         np->metrics[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]]; | 
					
						
							|  |  |  |         np->metrics[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]]; | 
					
						
							|  |  |  |         np->metrics[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]]; | 
					
						
							|  |  |  |         symbols += 2; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     np = nodes; | 
					
						
							|  |  |  |     np->encstate = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |     // Compute and sort branch metrics from root node */
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     ENCODE(lsym, np->encstate);  // 0-branch (LSB is 0)
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     m0 = np->metrics[lsym]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Now do the 1-branch. To save another ENCODE call here and
 | 
					
						
							|  |  |  |      * inside the loop, we assume that both polynomials are odd, | 
					
						
							|  |  |  |      * providing complementary pairs of branch symbols. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      * This code should be modified if a systematic code were used. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     m1 = np->metrics[3 ^ lsym]; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     if (m0 > m1) { | 
					
						
							|  |  |  |         np->tm[0] = m0;  // 0-branch has better metric
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         np->tm[1] = m1; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |         np->tm[0] = m1;  // 1-branch is better
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         np->tm[1] = m0; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |         np->encstate++;  // Set low bit
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     np->i = 0;  // Start with best branch
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |     maxcycles *= nbits; | 
					
						
							|  |  |  |     np->gamma = t = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Start the Fano decoder
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     for (i = 1; i <= maxcycles; i++) { | 
					
						
							|  |  |  |         if ((int)(np - nodes) > (int)*maxnp) *maxnp = (int)(np - nodes); | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Look forward */
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         ngamma = np->gamma + np->tm[np->i]; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |         if (ngamma >= t) { | 
					
						
							|  |  |  |             if (np->gamma < t + delta) {  // Node is acceptable
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                 /* First time we've visited this node;
 | 
					
						
							|  |  |  |                  * Tighten threshold. | 
					
						
							|  |  |  |                  * | 
					
						
							|  |  |  |                  * This loop could be replaced with | 
					
						
							|  |  |  |                  *   t += delta * ((ngamma - t)/delta); | 
					
						
							|  |  |  |                  * but the multiply and divide are slower. | 
					
						
							|  |  |  |                  */ | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |                 while (ngamma >= t + delta) t += delta; | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |             // Move forward
 | 
					
						
							|  |  |  |             np[1].gamma = ngamma; | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             np[1].encstate = np->encstate << 1; | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |             if (++np == (lastnode + 1)) { | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |                 break;  // Done!
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Compute and sort metrics, starting with the
 | 
					
						
							|  |  |  |              * zero branch | 
					
						
							|  |  |  |              */ | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |             ENCODE(lsym, np->encstate); | 
					
						
							|  |  |  |             if (np >= tail) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                 /* The tail must be all zeroes, so don't
 | 
					
						
							|  |  |  |                  * bother computing the 1-branches here. | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |                 np->tm[0] = np->metrics[lsym]; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 m0 = np->metrics[lsym]; | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |                 m1 = np->metrics[3 ^ lsym]; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |                 if (m0 > m1) { | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |                     np->tm[0] = m0;  // 0-branch is better
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                     np->tm[1] = m1; | 
					
						
							|  |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |                     np->tm[0] = m1;  // 1-branch is better
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                     np->tm[1] = m0; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |                     np->encstate++;  // Set low bit
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |             np->i = 0; | 
					
						
							|  |  |  |             // Start with best branch
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         // Threshold violated, can't go forward
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |         for (;;) { | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  |             // Look backward
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |             if (np == nodes || np[-1].gamma < t) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                 /* Can't back up either.
 | 
					
						
							|  |  |  |                  * Relax threshold and and look | 
					
						
							|  |  |  |                  * forward again to better branch. | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |                 t -= delta; | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |                 if (np->i != 0) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                     np->i = 0; | 
					
						
							|  |  |  |                     np->encstate ^= 1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |             // Back up
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |             if (--np < tail && np->i != 1) { | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |                 np->i++;  // Search next best branch
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |                 np->encstate ^= 1; | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |             }  // else keep looking back
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     *metric = np->gamma;  // Return the final path metric
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Copy decoded data to user's buffer
 | 
					
						
							|  |  |  |     nbits >>= 3; | 
					
						
							|  |  |  |     np = &nodes[7]; | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     while (nbits-- != 0) { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  |         *data++ = np->encstate; | 
					
						
							|  |  |  |         np += 8; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     *cycles = i + 1; | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     free(nodes); | 
					
						
							| 
									
										
										
										
											2021-12-04 03:20:42 +00:00
										 |  |  |     if (i >= maxcycles) | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |         return -1;  // Decoder timed out
 | 
					
						
							| 
									
										
										
										
											2017-06-23 04:32:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-04 20:19:06 +00:00
										 |  |  |     return 0;  // Successful completion
 | 
					
						
							| 
									
										
										
										
											2016-06-11 21:34:36 +00:00
										 |  |  | } |