📄 v32rx.c
字号:
#line 1 "v32rx.F"
#include <stdio.h> /* sprintf */
#include <coro.h>
#include <complex.h>
#include <filters.h>
#line 1 "<<generated_fspecs>>"
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 <scramble.h>
#include <equalize.h>
#include <debug.h>
#include <sinegen.h>
#include <myaudio.h>
#include <mystdio.h>
#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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -