www.pudn.com > fast.zip > v32rx.C


#line 1 "v32rx.F" 
#include 	/* sprintf */ 
#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 6 "v32rx.F" 
#include  
#include  
#include  
#include  
#include  
#include  
 
#include "modem.h" 
#include "cancel.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 char *rate_strs[] = { "R1", "R2", "R3", "E3" };      /* indexed by mstate */ 
 
static sinegen *carrier; 
static coroutine *rx1_co, *rx2_co; 
static cfilter *fe_lpf; 
static equalizer *eqz; 
static scrambler *gpa; 
static decoder *dec; 
static traininggen *trn; 
static co_debugger *co_debug; 
static debugger *can_debug, *dt_debug, *acq_debug; 
static int timing, nextadj; 
static char ticker; 
 
static void tidyup(); 
static void getratesignals(); 
static ushort getrate(), getrwd(); 
static void reportrate(ushort); 
 
static void rx2_loop(), roundtrip(), rcvdata(); 
static void wt_tone(int, int, int, bool); 
static int wt_reversal(int, int); 
static complex getsymbol(); 
static void adjtiming(); 
static void traincanceller(); 
static complex gethalfsymb(); 
 
inline int gbit()	{ return callco(rx2_co); } 
inline void pbit(int b) { callco(rx1_co, b);	 } 
 
 
global void initrx() 
  { my_alarm(15);  /* 15 sec timeout */ 
    carrier = new sinegen(1800.0); 
    fe_lpf = new cfilter(lpf_fs); 
    eqz = new equalizer(0.25); 
    rx1_co = currentco; 
    rx2_co = new coroutine(rx2_loop); 
    gpa = new scrambler(GPA); 
    trn = new traininggen(gpa); 
    dec = new decoder; 
    // dec -> printtrellis("debugt1.txt"); 
    co_debug = new co_debugger(24000); 
    can_debug = new debugger(1, 24000); 
    dt_debug = new debugger(1, 4000); 
    acq_debug = new debugger(2, 24000); 
    atexit(tidyup); 
    getratesignals(); 
    dec -> setrate(rateword);		    /* tell decoder what bit rate to use */ 
    for (int i = 0; i < 128; i++) gbit();   /* discard 128 "1" bits (wait for trellis decoder to settle) */ 
    my_alarm(0);   /* cancel alarm */ 
  } 
 
static void tidyup() 
  { eqz -> print("debug_eqz.grap"); 
    dec -> printtrellis("debugt2.txt"); 
    co_debug -> print("debug_co.grap"); 
    can_debug -> print("debug_can.grap"); 
    dt_debug -> print("debug_dt.grap"); 
    acq_debug -> print("debug_acq.grap"); 
  } 
 
static void getratesignals() 
  { ushort wd; 
    for (int i=0; i<2; i++) 
      { wd = getrate();	    /* R1/R3 */ 
	reportrate(wd); 
      } 
    /* look for E */ 
    until ((wd & 0xf000) == 0xf000) wd = getrwd(); 
    unless (wd == rateword) giveup("failed to detect valid E3"); 
    reportrate(wd); 
  } 
 
static ushort getrate() 
  { ushort wd = getrwd(); 
l:  until ((wd & 0xf111) == 0x0111) wd = (wd << 1) | gbit(); 
    ushort rate = wd; 
    for (int i = 0; i < 16; i++)	/* look for 16 identical rate signals */ 
      { wd = getrwd(); 
	if (wd != rate) goto l; 
      } 
    return rate; 
  } 
 
static ushort getrwd() 
  { ushort wd; 
    for (int i = 0; i < 16; i++) wd = (wd << 1) | gbit(); 
    return wd; 
  } 
 
static void reportrate(ushort r) 
  { infomsg("<<< %s: rates = %04x", rate_strs[mstate-2], r); 
    rateword &= r; 
    mstate++;	/* from 2 to 3, or 4 to 5, or 5 to 6 */ 
  } 
 
global int getasync() 
  { int b = gbit(), nb = 0; 
    while (nb < 10 && b) { b = gbit(); nb++; } 
    if (b) return NOCHAR;  /* no char yet */ 
    int ch = 0; 
    for (int i = 0; i < 8; i++) 
      { int b = gbit(); 
	ch = (ch >> 1) | (b << 7); 
      } 
    return ch; 
  } 
 
static void rx2_loop() 
  { /* round-trip-delay calculation */ 
    carrier -> resetphase(); 
    roundtrip(); 
    /* train equalizer */ 
    carrier -> resetphase(); 
    rcvdata(); 
    /* train canceller */ 
    carrier -> resetphase(); 
    traincanceller(); 
    /* exchange data */ 
    rcvdata();			/* never returns */ 
  } 
 
static void roundtrip() 
  { setduplex(64*SYMBLEN); 
    timing = 0; ticker = 'a'; 
    eqz -> reset(); 
    wt_tone(0, 3, 100, true);			/* wait for stable AC... */    // WAS 50 
    int t1 = wt_reversal(0, 3);			/* then reversal to CA... */ 
    mstate++;	/* from 0 to 1 */ 
    wt_tone(3, 0, 100, false);			/* swallow CA... */ 
    int t2 = wt_reversal(3, 0);			/* wait for reversal to AC... */ 
    mstate++;	/* from 1 to 2 */ 
    int dt = t2 - t1; 
    setduplex(TRDELAY); 
    float ms = (float) (dt - 128*SYMBLEN) / (float) SAMPLERATE * 1000.0f; 
    char rtd[32]; sprintf(rtd, "%.1f", ms); infomsg("RTD = %sms (%d)", rtd, dt); 
  } 
 
static void rcvdata() 
  { timing = 0; ticker = 'A'; 
    eqz -> reset(); 
    wt_tone(0, 1, 230, true);			/* wait for stable AB... (S) */ 
    wt_reversal(0, 1);				/* then BA... (Sbar) */ 
    /* adj equalizer coeffs and symbol timing; use training sequence */ 
    int bc = SEG_2 + 2; 
    gpa -> reset();				/* reset scrambler before using trn */ 
    nextadj = samplecount + 2*SAMPLERATE; 
    while (bc < SEG_3 + 1024) 
      { 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('X'); 
    /* adj equalizer coeffs and symbol timing; use decoded data */ 
    dec -> reset(); 
    while (mstate == 2 || mstate >= 4) 
      { complex z = getsymbol();		/* get equalized symbol */ 
	int bits = dec -> decode(z);		/* decode into 2 or 3 bits */ 
	if (dec -> rate & rb_7200) pbit(gpa -> rev(bits >> 2)); 
	pbit(gpa -> rev((bits >> 1) & 1)); 
	pbit(gpa -> rev(bits & 1)); 
	complex ez = dec -> getez();		/* get exact (quantized) z */ 
	eqz -> update(ez-z);			/* update equalizer from data sequence */ 
	adjtiming();				/* adjust symbol timing */ 
      } 
  } 
 
static void wt_tone(int k0, int k1, int max, bool chk) 
  { /* wait for a stable tone */ 
    complex z0 = ztab2[k0], z1 = ztab2[k1]; 
    int bc = 0, cnt = 0; 
    until (cnt >= max && !(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 || !chk) cnt++; else cnt = 0; 
	eqz -> short_update(ez-z);		/* short update here */ 
      } 
    acq_debug -> tick(ticker++); 
  } 
 
static int wt_reversal(int k0, int k1) 
  { /* wait for a phase reversal */ 
    complex z0 = ztab2[k0], z1 = ztab2[k1]; 
    int bc = 0; int t; 
    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) { t = samplecount; rev = true; } 
	eqz -> short_update(ez-z);		/* short update here */ 
      } 
    acq_debug -> tick(ticker++); 
    return t; 
  } 
 
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 void adjtiming() 
  { if (after(samplecount, nextadj)) 
      { int dt = eqz -> getdt(); 
	dt_debug -> insert(dt); 
	if (dt > 0) { timing--; eqz -> shift(-1); } 
	if (dt < 0) { timing++; eqz -> shift(+1); } 
	nextadj = samplecount + 2*SAMPLERATE;	/* adjust every 2 secs */ 
      } 
  } 
 
static void traincanceller() 
  { /* train canceller at half-symbol intervals */ 
    while (mstate == 3) 
      { complex yz = gethalfsymb(); 
	can -> update(yz); 
	can_debug -> insert(power(yz)); 
      } 
  } 
 
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 */ 
      } 
    complex pe = can -> get();		/* subtract predicted echo */ 
    return yz - pe; 
  }