www.pudn.com > slow.zip > v29rx.C


/********************************************************* 
********************************************************** 
	v29rx.c 
********************************************************** 
**********************************************************/ 
#line 1 "v29rx.F" 
/* Modem for MIPS   AJF	  March 1998 
   V.29 receive routines */ 
 
#include  
 
#include  
#include  
#line 1 "<>" 
 
static float _fstepf_1(filter *fi, float x) 
  { /* /usr/fisher/mipsbin/mkfilter -Bu -Lp -o 4 -a 0.125 -l */ 
    float *v = fi -> v; 
    v[0] = v[1]; v[1] = v[2]; v[2] = v[3]; v[3] = v[4];  
    v[4] =    (  1.0209480791e-02 * x) 
            + ( -0.1203895999 * v[0]) + (  0.7244708295 * v[1]) 
            + ( -1.7358607092 * v[2]) + (  1.9684277869 * v[3]); 
    return    (v[0] + v[4]) + 4 * (v[1] + v[3]) + 6 * v[2]; 
  } 
 
static fspec _fspecs_1 = { 4, 4, _fstepf_1 }; 
 
#line 8 "v29rx.F" 
#include  
#include  
#include  
#include  
#include  
 
#include "modem.h" 
#include "coder.h" 
 
#define THRESHOLD 1.0f	/* sqr of radius of error circle */ 
 
static fspec *lpf_fs = (&_fspecs_1);   /* low-pass at 1200 Hz */ 
 
static bool inited = false;	/* statically initialized */ 
 
static sinegen *carrier; 
static coroutine *bitco; 
static cfilter *fe_lpf; 
static scrambler *scr; 
static equalizer *eqz; 
static decoder *dec; 
static traininggen *trn; 
static co_debugger *co_debug; 
static debugger *acq_debug; 
static int timing, nextadj; 
 
static void tidydebug(), bitloop(), wt_tone(), wt_reversal(), train_eqz(), dataloop(); 
static complex getsymbol(), gethalfsymb(); 
static void adjtiming(); 
 
 
global void initrx_v29() 
  { unless (inited) 
      { /* perform once-only initialization */ 
	carrier = new sinegen(1700.0); 
	bitco = new coroutine(bitloop); 
	fe_lpf = new cfilter(lpf_fs); 
	scr = new scrambler(GPC); 
	eqz = new equalizer(0.5);   /* was 0.25; V.29 has short training sequence so needs fast equalization */ 
	dec = new decoder(); 
	trn = new traininggen; 
	co_debug = new co_debugger(24000); 
	acq_debug = new debugger(2, 4000); 
	atexit(tidydebug); 
	inited = true; 
      } 
    bitco -> reset(); 
    for (int i = 0; i < 144; i++) getbit();	/* scrambled 1s */ 
  } 
 
static void tidydebug() 
  { co_debug -> print("debug_co.grap"); 
    acq_debug -> print("debug_acq.grap"); 
    eqz -> print("debug_eqz.grap"); 
  } 
 
global int getbit()		/* bit input */ 
  { return callco(bitco); 
  } 
 
static void bitloop() 
  { wt_tone();					/* look for stable ABAB... */ 
    wt_reversal();				/* look for CDCD... */ 
    train_eqz(); 
    dataloop(); 
  } 
 
static void wt_tone() 
  { /* wait for a stable ABAB... */ 
    timing = 0; eqz -> reset(); 
    complex z0 = complex(-3.0f, 0.0f),	/* A */ 
	    z1 = complex(1.0f, -1.0f);	/* B */ 
    int bc = 0, cnt = 0; 
    until (cnt >= 64 && !(bc & 1)) 
      { complex z = getsymbol();		/* get equalized symbol */ 
	complex ez = (bc++ & 1) ? z1 : z0;	/* expected z */ 
	float p = power(z-ez); 
	acq_debug -> insert(z.re, p); 
	if (p < THRESHOLD) cnt++; else cnt = 0; 
	eqz -> short_update(ez-z);		/* short update here */ 
      } 
    acq_debug -> tick('A'); 
  } 
 
static void wt_reversal() 
  { /* wait for a phase reversal */ 
    complex z0 = complex(-3.0f, 0.0f),	/* A */ 
	    z1 = complex(1.0f, -1.0f);	/* B */ 
    int bc = 0; 
    bool rev = false; 
    until (rev & !(bc & 1)) 
      { complex z = getsymbol();		/* get equalized symbol */ 
	complex ez = (bc++ & 1) ? z1 : z0;	/* expected z */ 
	float p = power(z-ez); 
	acq_debug -> insert(z.re, p); 
	if (p >= THRESHOLD) rev = true; 
	eqz -> short_update(ez-z);		/* short update here */ 
      } 
    acq_debug -> tick('B'); 
  } 
 
static void train_eqz() 
  { /* adj equalizer coeffs and symbol timing; use training sequence */ 
    nextadj = samplecount + 2*SAMPLERATE; 
    int bc = SEG_3;					/* need to start here because of scrambler in training gen! */ 
    trn -> reset(); trn -> get(bc++); trn -> get(bc++); /* but we've already read the first 2 symbols */ 
    while (bc < SEG_4) 
      { complex z = getsymbol();		/* get equalized symbol */ 
	complex ez = trn -> get(bc++);		/* update equalizer using training sequence */ 
	float p = power(z-ez); 
	acq_debug -> insert(z.re, p); 
	eqz -> update(ez-z); 
	adjtiming();				/* adjust symbol timing */ 
      } 
    acq_debug -> tick('C'); 
  } 
 
static void dataloop() 
  { /* adj equalizer coeffs and symbol timing; use decoded data */ 
    scr -> reset(); dec -> reset(); 
    for (;;) 
      { complex z = getsymbol();		/* get equalized symbol */ 
	int bits = dec -> decode(z);		/* get 3 bits */ 
	for (int i = 0; i < 3; i++) 
	  { int b = scr -> rev((bits >> 2) & 1);	/* unscramble */ 
	    callco(currentco -> creator, b);		/* return the bit */ 
	    bits <<= 1; 
	  } 
	complex ez = dec -> getez();		/* get exact (quantized) z */ 
	eqz -> update(ez-z);			/* update equalizer from data sequence */ 
	adjtiming();				/* adjust symbol timing */ 
      } 
  } 
 
static complex getsymbol() 
  { for (int j = timing; j < 2; j++)		/* timing is -1, 0 or +1 */ 
      { complex yz = gethalfsymb(); 
	eqz -> insert(yz);			/* half-point equalization */ 
      } 
    timing = 0; 
    complex z = eqz -> get(); 
    co_debug -> insert(z); 
    return z; 
  } 
 
static complex gethalfsymb() 
  { /* sample at half-symbol intervals */ 
    complex yz; 
    for (int k = 0; k < SYMBLEN/2; k++) 
      { float x = insample(); 
	complex cz = carrier -> cnext(); 
	yz = fe_lpf -> fstep(x*cz);		/* translate to baseband */ 
      } 
    return yz; 
  } 
 
static void adjtiming() 
  { if (after(samplecount, nextadj)) 
      { int dt = eqz -> getdt(); 
	if (dt > 0) { timing--; eqz -> shift(-1); } 
	if (dt < 0) { timing++; eqz -> shift(+1); } 
	nextadj = samplecount + 2*SAMPLERATE;	/* adjust every 2 secs */ 
      } 
  }