1 /* K=9 r=1/2 Viterbi decoder in portable C 2 * Copyright Feb 2004, Phil Karn, KA9Q 3 * May be used under the terms of the GNU Lesser General Public License (LGPL) 4 */ 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <memory.h> 8 #include "fec.h" 9 10 typedef union { unsigned int w[256]; } metric_t; 11 typedef union { unsigned long w[8];} decision_t; 12 13 static union { unsigned char c[128]; } Branchtab29[2]; 14 static int Init = 0; 15 16 /* State info for instance of Viterbi decoder */ 17 struct v29 { 18 metric_t metrics1; /* path metric buffer 1 */ 19 metric_t metrics2; /* path metric buffer 2 */ 20 decision_t *dp; /* Pointer to current decision */ 21 metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */ 22 decision_t *decisions; /* Beginning of decisions for block */ 23 }; 24 25 /* Initialize Viterbi decoder for start of new frame */ 26 int init_viterbi29_port(void *p,int starting_state){ 27 struct v29 *vp = p; 28 int i; 29 30 if(p == NULL) 31 return -1; 32 for(i=0;i<256;i++) 33 vp->metrics1.w[i] = 63; 34 35 vp->old_metrics = &vp->metrics1; 36 vp->new_metrics = &vp->metrics2; 37 vp->dp = vp->decisions; 38 vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */ 39 return 0; 40 } 41 42 void set_viterbi29_polynomial_port(int polys[2]){ 43 int state; 44 45 for(state=0;state < 128;state++){ 46 Branchtab29[0].c[state] = (polys[0] < 0) ^ parity((2*state) & abs(polys[0])) ? 255 : 0; 47 Branchtab29[1].c[state] = (polys[1] < 0) ^ parity((2*state) & abs(polys[1])) ? 255 : 0; 48 } 49 Init++; 50 } 51 52 53 /* Create a new instance of a Viterbi decoder */ 54 void *create_viterbi29_port(int len){ 55 struct v29 *vp; 56 57 if(!Init){ 58 int polys[2] = {V29POLYA,V29POLYB}; 59 set_viterbi29_polynomial_port(polys); 60 } 61 if((vp = (struct v29 *)malloc(sizeof(struct v29))) == NULL) 62 return NULL; 63 64 if((vp->decisions = (decision_t *)malloc((len+8)*sizeof(decision_t))) == NULL){ 65 free(vp); 66 return NULL; 67 } 68 init_viterbi29_port(vp,0); 69 70 return vp; 71 } 72 73 74 /* Viterbi chainback */ 75 int chainback_viterbi29_port( 76 void *p, 77 unsigned char *data, /* Decoded output data */ 78 unsigned int nbits, /* Number of data bits */ 79 unsigned int endstate){ /* Terminal encoder state */ 80 struct v29 *vp = p; 81 decision_t *d; 82 83 if(p == NULL) 84 return -1; 85 86 d = vp->decisions; 87 /* Make room beyond the end of the encoder register so we can 88 * accumulate a full byte of decoded data 89 */ 90 endstate %= 256; 91 92 /* The store into data[] only needs to be done every 8 bits. 93 * But this avoids a conditional branch, and the writes will 94 * combine in the cache anyway 95 */ 96 d += 8; /* Look past tail */ 97 while(nbits-- != 0){ 98 int k; 99 100 k = (d[nbits].w[(endstate)/32] >> (endstate%32)) & 1; 101 data[nbits>>3] = endstate = (endstate >> 1) | (k << 7); 102 } 103 return 0; 104 } 105 106 107 /* Delete instance of a Viterbi decoder */ 108 void delete_viterbi29_port(void *p){ 109 struct v29 *vp = p; 110 111 if(vp != NULL){ 112 free(vp->decisions); 113 free(vp); 114 } 115 } 116 117 /* C-language butterfly */ 118 #define BFLY(i) {\ 119 unsigned int metric,m0,m1,decision;\ 120 metric = (Branchtab29[0].c[i] ^ sym0) + (Branchtab29[1].c[i] ^ sym1);\ 121 m0 = vp->old_metrics->w[i] + metric;\ 122 m1 = vp->old_metrics->w[i+128] + (510 - metric);\ 123 decision = (signed int)(m0-m1) > 0;\ 124 vp->new_metrics->w[2*i] = decision ? m1 : m0;\ 125 d->w[i/16] |= decision << ((2*i)&31);\ 126 m0 -= (metric+metric-510);\ 127 m1 += (metric+metric-510);\ 128 decision = (signed int)(m0-m1) > 0;\ 129 vp->new_metrics->w[2*i+1] = decision ? m1 : m0;\ 130 d->w[i/16] |= decision << ((2*i+1)&31);\ 131 } 132 133 /* Update decoder with a block of demodulated symbols 134 * Note that nbits is the number of decoded data bits, not the number 135 * of symbols! 136 */ 137 138 int update_viterbi29_blk_port(void *p,unsigned char *syms,int nbits){ 139 struct v29 *vp = p; 140 decision_t *d; 141 142 if(p == NULL) 143 return -1; 144 145 d = (decision_t *)vp->dp; 146 while(nbits--){ 147 void *tmp; 148 unsigned char sym0,sym1; 149 int i; 150 151 for(i=0;i<8;i++) 152 d->w[i] = 0; 153 sym0 = *syms++; 154 sym1 = *syms++; 155 156 for(i=0;i<128;i++) 157 BFLY(i); 158 159 d++; 160 tmp = vp->old_metrics; 161 vp->old_metrics = vp->new_metrics; 162 vp->new_metrics = tmp; 163 } 164 vp->dp = d; 165 return 0; 166 } 167