1999-01-31 09:06:09 +00:00
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
/*
|
|
|
|
|
******************************************************************************
|
|
|
|
|
|
|
|
|
|
Fax program for ISDN.
|
1999-01-31 09:06:09 +00:00
|
|
|
|
|
|
|
|
|
This is the V.29 demodulator. The module handles the training phase as well
|
|
|
|
|
as the final data transmission.
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
Copyright (C) 1999 Oliver Eichler [oliver.eichler@regensburg.netsurf.de
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
******************************************************************************
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ifax/ifax.h>
|
|
|
|
|
|
|
|
|
|
#include "../include/ifax/modules/V.29_demod.h"
|
|
|
|
|
|
|
|
|
|
#define PHASEINC1700HZ 15474
|
1999-01-31 09:06:09 +00:00
|
|
|
|
#define INTERVAL_CNT 2
|
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
1999-01-31 17:11:18 +00:00
|
|
|
|
#define X1 0x1555
|
|
|
|
|
#define X2 0x2AAA
|
|
|
|
|
#define X3 0x4000
|
|
|
|
|
#define X4 0x5555
|
|
|
|
|
#define X5 0x6AAA
|
|
|
|
|
#define X6 0x7FFF
|
|
|
|
|
#define Y1 0x1555
|
|
|
|
|
#define Y2 0x2AAA
|
|
|
|
|
#define Y3 0x4000
|
|
|
|
|
#define Y4 0x5555
|
|
|
|
|
#define Y5 0x6AAA
|
|
|
|
|
#define Y6 0x7FFF
|
|
|
|
|
|
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
#define DEG0 0x0000
|
|
|
|
|
#define DEG45 0x2000
|
|
|
|
|
#define DEG90 0x4000
|
|
|
|
|
#define DEG135 0x6000
|
|
|
|
|
#define DEG180 0x8000
|
|
|
|
|
#define DEG225 0xA000
|
|
|
|
|
#define DEG270 0xC000
|
|
|
|
|
#define DEG315 0xE000
|
|
|
|
|
|
|
|
|
|
#define A9600 8
|
|
|
|
|
#define B9600 15
|
|
|
|
|
|
|
|
|
|
#define NOSYMB 3
|
|
|
|
|
#define NOSAMP 3
|
|
|
|
|
|
|
|
|
|
#define L_MIN 0x0006
|
|
|
|
|
#define L_2 0x0013
|
|
|
|
|
|
|
|
|
|
#define NIL 0x0
|
1999-02-21 12:19:37 +00:00
|
|
|
|
#define ESTIMATEGAIN 0x1
|
|
|
|
|
#define LISTEN 0x2
|
|
|
|
|
#define PHASEHUNT 0x3
|
|
|
|
|
|
|
|
|
|
#define TAU50
|
|
|
|
|
#undef TAU30
|
|
|
|
|
#ifdef TAU50
|
|
|
|
|
#define AGCESTDLY 50
|
|
|
|
|
#define TAU 0x0288
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef TAU30
|
|
|
|
|
#define AGCESTDLY 30
|
|
|
|
|
#define TAU 0x0432
|
|
|
|
|
#endif
|
|
|
|
|
#define B 0x7FFF
|
|
|
|
|
#define LEVEL 0x16D6
|
|
|
|
|
#define LEVEL63 0x0E63
|
|
|
|
|
#define SQRT_LEVEL63 0x2AE9
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
signed short Re;
|
|
|
|
|
signed short Im;
|
|
|
|
|
unsigned short angl;
|
|
|
|
|
}
|
|
|
|
|
V29_symbol;
|
|
|
|
|
|
|
|
|
|
V29_symbol V29_symb_tbl[] =
|
|
|
|
|
{
|
1999-01-31 17:11:18 +00:00
|
|
|
|
{0x4000, 0x0000, DEG0}, /* P=000 Q=0 (0) */
|
|
|
|
|
{0x6AAA, 0x0000, DEG0}, /* P=000 Q=1 (0) */
|
|
|
|
|
{0x1555, 0x1555, DEG45}, /* P=001 Q=0 (45) */
|
|
|
|
|
{0x4000, 0x4000, DEG45}, /* P=001 Q=1 (45) */
|
|
|
|
|
{0x0000, 0x4000, DEG90}, /* P=010 Q=0 (90) */
|
|
|
|
|
{0x0000, 0x6AAA, DEG90}, /* P=010 Q=1 (90) */
|
|
|
|
|
{0xEAAB, 0x1555, DEG135}, /* P=011 Q=0 (135) */
|
|
|
|
|
{0xC000, 0x4000, DEG135}, /* P=011 Q=1 (135) */
|
|
|
|
|
{0xC000, 0x0000, DEG180}, /* P=100 Q=0 (180) */
|
|
|
|
|
{0x9556, 0x0000, DEG180}, /* P=100 Q=1 (180) */
|
|
|
|
|
{0xEAAB, 0xEAAB, DEG225}, /* P=101 Q=0 (225) */
|
|
|
|
|
{0xC000, 0xC000, DEG225}, /* P=101 Q=1 (225) */
|
|
|
|
|
{0x0000, 0xC000, DEG270}, /* P=110 Q=0 (270) */
|
|
|
|
|
{0x0000, 0x9556, DEG270}, /* P=110 Q=1 (270) */
|
|
|
|
|
{0x1555, 0xEAAB, DEG315}, /* P=111 Q=0 (315) */
|
|
|
|
|
{0x4000, 0xC000, DEG315}, /* P=111 Q=1 (315) */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
1999-02-21 12:19:37 +00:00
|
|
|
|
unsigned short agc_gain;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
unsigned short w;
|
|
|
|
|
int phi;
|
|
|
|
|
short a;
|
|
|
|
|
short power;
|
|
|
|
|
int state;
|
|
|
|
|
short dem_lpf_buf[NOSYMB * NOSAMP];
|
|
|
|
|
short dem_re[NOSYMB * NOSAMP];
|
|
|
|
|
short dem_im[NOSYMB * NOSAMP];
|
|
|
|
|
unsigned short dem_angl[2 * NOSYMB * NOSAMP];
|
|
|
|
|
int dem_angl_dif[NOSYMB * NOSAMP];
|
|
|
|
|
int dem_angl_dist[NOSYMB * NOSAMP];
|
|
|
|
|
int dem_index;
|
|
|
|
|
int smpl_cnt;
|
|
|
|
|
V29_symbol current_symbol;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
V29demod_private;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
short dem_lpf_coef[] = {0x203E, 0x3F82, 0x203E};
|
1999-01-31 17:11:18 +00:00
|
|
|
|
int FirstQuadTbl[] = {0,1,2,3,4,5,2,3};
|
|
|
|
|
int ReMinusTbl[] = {8,9,6,7,4,5};
|
|
|
|
|
int ImMinusTbl[] = {0,1,14,15,12,13,10,11,8,9};
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
short DCD (short s, V29demod_private * priv);
|
|
|
|
|
short Demod (short s, V29demod_private * priv);
|
|
|
|
|
short FindSeq2(V29demod_private * priv);
|
|
|
|
|
short PhaseHuntSeq2(V29demod_private * priv);
|
1999-02-21 12:19:37 +00:00
|
|
|
|
short agc_dummy(short s, V29demod_private * priv);
|
1999-01-31 17:11:18 +00:00
|
|
|
|
short SymbolMapping(V29demod_private * priv);
|
1999-02-21 12:19:37 +00:00
|
|
|
|
void agc_estimate(V29demod_private *priv);
|
1999-01-31 09:06:09 +00:00
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
V29demod_destroy (ifax_modp self)
|
|
|
|
|
{
|
|
|
|
|
/* V29demod_private *priv=(V29demod_private *)self->private; */
|
|
|
|
|
|
|
|
|
|
free (self->private);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
V29demod_command (ifax_modp self, int cmd, va_list cmds)
|
|
|
|
|
{
|
|
|
|
|
return 0; /* Not yet used. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
V29demod_handle (ifax_modp self, void *data, size_t length)
|
|
|
|
|
{
|
|
|
|
|
V29demod_private *priv = (V29demod_private *) self->private;
|
|
|
|
|
int n;
|
|
|
|
|
short *ps_s = data;
|
1999-02-21 12:19:37 +00:00
|
|
|
|
static short max = 0;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
for (n = 0; n < length; n++)
|
|
|
|
|
{
|
1999-02-21 12:19:37 +00:00
|
|
|
|
|
|
|
|
|
if(max<*ps_s){
|
|
|
|
|
max = *ps_s;
|
|
|
|
|
printf("max %i\n",max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ps_s = (*ps_s*0x1300)>>15;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
switch (priv->state)
|
|
|
|
|
{
|
1999-01-31 09:06:09 +00:00
|
|
|
|
case NIL: /* idle and measure power */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
DCD (*ps_s, priv);
|
|
|
|
|
|
|
|
|
|
ps_s++;
|
|
|
|
|
break;
|
|
|
|
|
|
1999-02-21 12:19:37 +00:00
|
|
|
|
case ESTIMATEGAIN: /* estimate initial input gain */
|
|
|
|
|
DCD (*ps_s, priv);
|
|
|
|
|
agc_estimate(priv);
|
|
|
|
|
ps_s++;
|
|
|
|
|
break;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
case LISTEN: /* try to detect Segment 2 */
|
1999-02-21 12:19:37 +00:00
|
|
|
|
*ps_s = agc_dummy(*ps_s, priv);
|
1999-01-25 20:29:53 +00:00
|
|
|
|
DCD (*ps_s, priv);
|
|
|
|
|
Demod (*ps_s, priv);
|
|
|
|
|
FindSeq2(priv);
|
|
|
|
|
|
|
|
|
|
ps_s++;
|
|
|
|
|
break;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
case PHASEHUNT: /* synchronize the carrier phase */
|
1999-02-21 12:19:37 +00:00
|
|
|
|
*ps_s = agc_dummy(*ps_s, priv);
|
1999-01-25 20:29:53 +00:00
|
|
|
|
DCD (*ps_s, priv);
|
|
|
|
|
Demod (*ps_s, priv);
|
1999-01-31 17:11:18 +00:00
|
|
|
|
if(priv->smpl_cnt == 0){
|
|
|
|
|
PhaseHuntSeq2(priv);
|
|
|
|
|
SymbolMapping(priv);
|
|
|
|
|
priv->smpl_cnt = 3;
|
|
|
|
|
}
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
1999-01-31 17:11:18 +00:00
|
|
|
|
priv->smpl_cnt--;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
ps_s++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
V29demod_demand (ifax_modp self, size_t demand)
|
|
|
|
|
{
|
|
|
|
|
V29demod_private *priv = (V29demod_private *) self->private;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
V29demod_construct (ifax_modp self, va_list args)
|
|
|
|
|
{
|
|
|
|
|
V29demod_private *priv;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (NULL == (priv = self->private = malloc (sizeof (V29demod_private))))
|
|
|
|
|
return 1;
|
|
|
|
|
self->destroy = V29demod_destroy;
|
|
|
|
|
self->handle_input = V29demod_handle;
|
|
|
|
|
self->command = V29demod_command;
|
|
|
|
|
self->handle_demand = V29demod_demand;
|
|
|
|
|
|
1999-02-21 12:19:37 +00:00
|
|
|
|
priv->w = 0; /* the carrier's omega */
|
|
|
|
|
priv->phi = 0; /* phi to achive carrier sync. */
|
|
|
|
|
priv->a = TAU;
|
|
|
|
|
priv->state = NIL; /* state variable for the demodulators statemachine*/
|
|
|
|
|
priv->dem_index = 0; /* index of the actual demodulated sample within
|
|
|
|
|
the demodulator buffers */
|
|
|
|
|
priv->smpl_cnt = -1; /* offset for symbol sync.
|
|
|
|
|
-1 stands for 'no symb. found' */
|
|
|
|
|
priv->agc_gain = 0x0D55; /* equals 0.8333 in (4:12) format */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
|
1999-02-21 12:19:37 +00:00
|
|
|
|
short agc_dummy(short s, V29demod_private * priv)
|
1999-01-31 09:06:09 +00:00
|
|
|
|
{
|
1999-02-21 12:19:37 +00:00
|
|
|
|
return (s*priv->agc_gain)>>12;
|
1999-01-31 09:06:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-02-21 12:19:37 +00:00
|
|
|
|
void agc_estimate(V29demod_private *priv)
|
|
|
|
|
{
|
|
|
|
|
static int cnt;
|
|
|
|
|
long num;
|
|
|
|
|
short g;
|
|
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
|
if(cnt == AGCESTDLY){
|
|
|
|
|
num = intsqrt(LEVEL63);
|
|
|
|
|
num <<= 12;
|
|
|
|
|
g = num/intsqrt(priv->power);
|
|
|
|
|
priv->agc_gain = g;
|
|
|
|
|
printf("I would guess gain is %04X\n", g);
|
|
|
|
|
priv->state = LISTEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
1999-01-31 09:06:09 +00:00
|
|
|
|
short Demod (short s, V29demod_private * priv)
|
1999-01-25 20:29:53 +00:00
|
|
|
|
{
|
|
|
|
|
static int cnt = 0;
|
|
|
|
|
int sum_Re = 0;
|
|
|
|
|
int sum_Im = 0;
|
|
|
|
|
unsigned short w;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/*modulo increment of sample index */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
priv->dem_index = (priv->dem_index < NOSYMB * NOSAMP - 1) ?
|
|
|
|
|
(priv->dem_index + 1) : 0;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* calulate phase corrected omega */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
w = priv->w + priv->phi;
|
1999-01-31 09:06:09 +00:00
|
|
|
|
|
|
|
|
|
/* demodulate signal. The lowpass filter supresses frequencies
|
|
|
|
|
at 2*f_c */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
switch (cnt)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
priv->dem_lpf_buf[0] = (s * intcos (w)) >> 15;
|
|
|
|
|
priv->dem_lpf_buf[1] = (s * intsin (w)) >> 15;
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[0] * dem_lpf_coef[0];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[1] * dem_lpf_coef[0];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[2] * dem_lpf_coef[2];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[3] * dem_lpf_coef[2];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[4] * dem_lpf_coef[1];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[5] * dem_lpf_coef[1];
|
|
|
|
|
cnt++;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
priv->dem_lpf_buf[2] = (s * intcos (w)) >> 15;
|
|
|
|
|
priv->dem_lpf_buf[3] = (s * intsin (w)) >> 15;
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[0] * dem_lpf_coef[1];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[1] * dem_lpf_coef[1];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[2] * dem_lpf_coef[0];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[3] * dem_lpf_coef[0];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[4] * dem_lpf_coef[2];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[5] * dem_lpf_coef[2];
|
|
|
|
|
cnt++;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
priv->dem_lpf_buf[4] = (s * intcos (w)) >> 15;
|
|
|
|
|
priv->dem_lpf_buf[5] = (s * intsin (w)) >> 15;
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[0] * dem_lpf_coef[2];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[1] * dem_lpf_coef[2];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[2] * dem_lpf_coef[1];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[3] * dem_lpf_coef[1];
|
|
|
|
|
sum_Re += priv->dem_lpf_buf[4] * dem_lpf_coef[0];
|
|
|
|
|
sum_Im += priv->dem_lpf_buf[5] * dem_lpf_coef[0];
|
|
|
|
|
cnt = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-31 17:11:18 +00:00
|
|
|
|
sum_Re = sum_Re >> 14;
|
|
|
|
|
sum_Im = sum_Im >> 14;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
priv->dem_re[priv->dem_index] = sum_Re;
|
|
|
|
|
priv->dem_im[priv->dem_index] = sum_Im;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* calculate the absolute angle of the signal */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
priv->dem_angl[priv->dem_index] = intatan (sum_Im, sum_Re);
|
|
|
|
|
priv->dem_angl[priv->dem_index + NOSYMB * NOSAMP] =
|
|
|
|
|
priv->dem_angl[priv->dem_index];
|
|
|
|
|
|
|
|
|
|
priv->w += PHASEINC1700HZ;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-01-31 17:11:18 +00:00
|
|
|
|
short SymbolMapping(V29demod_private * priv)
|
|
|
|
|
{
|
|
|
|
|
short re = priv->dem_re[priv->dem_index];
|
|
|
|
|
short im = priv->dem_im[priv->dem_index];
|
|
|
|
|
short abs_re;
|
|
|
|
|
short abs_im;
|
|
|
|
|
short tmp;
|
|
|
|
|
int d1, d2, point;
|
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
|
|
abs_re = re < 0 ? -re : re;
|
|
|
|
|
abs_im = im < 0 ? -im : im;
|
|
|
|
|
|
|
|
|
|
if(abs_re < abs_im){
|
|
|
|
|
tmp = abs_re;
|
|
|
|
|
abs_re = abs_im;
|
|
|
|
|
abs_im = tmp;
|
|
|
|
|
offset = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(abs_re < X4){
|
|
|
|
|
if((abs_re+abs_im) < X2+Y2){
|
|
|
|
|
d1 = (abs_re - X3)*(abs_re - X3) + abs_im*abs_im;
|
|
|
|
|
d2 = (abs_re - X1)*(abs_re - X1) + (abs_im-Y1)*(abs_im-Y1);
|
|
|
|
|
point = d1 > d2 ? 2 : 0;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
d1 = (abs_re - X3)*(abs_re - X3) + abs_im*abs_im;
|
|
|
|
|
d2 = (abs_re - X3)*(abs_re - X3) + (abs_im-Y3)*(abs_im-Y3);
|
|
|
|
|
point = d1 > d2 ? 3 : 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
d1 = (abs_re - X5)*(abs_re - X5) + abs_im*abs_im;
|
|
|
|
|
d2 = (abs_re - X3)*(abs_re - X3) + (abs_im-Y3)*(abs_im-Y3);
|
|
|
|
|
point = d1 > d2 ? 3 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
point = FirstQuadTbl[offset+point];
|
|
|
|
|
if(re < 0) point = ReMinusTbl[point];
|
|
|
|
|
if(im < 0) point = ImMinusTbl[point];
|
|
|
|
|
|
1999-02-21 12:19:37 +00:00
|
|
|
|
printf("%i\n",point);
|
1999-01-31 17:11:18 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
short
|
|
|
|
|
FindSeq2(V29demod_private * priv)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* calculate the relative angle between two symbols */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
priv->dem_angl_dif[priv->dem_index] =
|
|
|
|
|
priv->dem_angl[priv->dem_index + NOSYMB * NOSAMP] -
|
|
|
|
|
priv->dem_angl[priv->dem_index + NOSYMB * NOSAMP - 3];
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* calculate the absolute distance to the expected 135<33> phase difference */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
if(priv->dem_angl_dif[priv->dem_index] > 0){
|
|
|
|
|
priv->dem_angl_dist[priv->dem_index] = priv->dem_angl_dif[priv->dem_index] - DEG135;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
priv->dem_angl_dist[priv->dem_index] = DEG135 + priv->dem_angl_dif[priv->dem_index];
|
|
|
|
|
}
|
|
|
|
|
abs(priv->dem_angl_dist[priv->dem_index]) ;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* check for sequence 2 every NOSYMB*NOSAMP */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
if(priv->dem_index == 0)
|
|
|
|
|
{
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
static int flag = INTERVAL_CNT;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* find minima within angle distance buffer */
|
1999-01-25 20:29:53 +00:00
|
|
|
|
res |= (priv->dem_angl_dist[0] < priv->dem_angl_dist[NOSYMB*NOSAMP-1]) &&
|
|
|
|
|
(priv->dem_angl_dist[0] < priv->dem_angl_dist[1]) ? 0 : 1;
|
|
|
|
|
res <<= 1;
|
|
|
|
|
for(i=1; i< NOSYMB*NOSAMP-1; i++){
|
|
|
|
|
res |= (priv->dem_angl_dist[i] < priv->dem_angl_dist[i-1]) &&
|
|
|
|
|
(priv->dem_angl_dist[i] < priv->dem_angl_dist[i+1]) ? 0 : 1;
|
|
|
|
|
res <<= 1;
|
|
|
|
|
}
|
|
|
|
|
res |= (priv->dem_angl_dist[NOSYMB*NOSAMP-1] < priv->dem_angl_dist[NOSYMB*NOSAMP-2]) &&
|
|
|
|
|
(priv->dem_angl_dist[NOSYMB*NOSAMP-1] < priv->dem_angl_dist[0]) ? 0 : 1;
|
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
/* valid received symbols will produce the binary patterns:
|
|
|
|
|
|
|
|
|
|
110110110b
|
|
|
|
|
101101101b
|
|
|
|
|
011011011b
|
|
|
|
|
|
|
|
|
|
Depending on the point of maximum likelihood for sampling, given by
|
|
|
|
|
the positions of '0''s in the result line, the initial value for
|
|
|
|
|
the sample counter is set.
|
|
|
|
|
|
|
|
|
|
Depending on the absolute phases of the symbols the angle difference
|
|
|
|
|
can be either 135<EFBFBD> or 225<EFBFBD>. As the distance is only derived for 135<EFBFBD>
|
|
|
|
|
the received signal is turned by 180<EFBFBD> after INTERVAL_CNT (>0) decision
|
|
|
|
|
intervals.
|
|
|
|
|
*/
|
1999-01-25 20:29:53 +00:00
|
|
|
|
if (res == 0x1B6) priv->smpl_cnt = 1;
|
|
|
|
|
if (res == 0x16B) priv->smpl_cnt = 0;
|
|
|
|
|
if (res == 0x0DB) priv->smpl_cnt = 5;
|
|
|
|
|
if (priv->smpl_cnt < 0){
|
|
|
|
|
if(flag){
|
1999-01-31 09:06:09 +00:00
|
|
|
|
flag--;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
priv->phi += DEG180;
|
|
|
|
|
priv->phi &= 0x0000FFFF;
|
1999-01-31 09:06:09 +00:00
|
|
|
|
flag = INTERVAL_CNT;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-01-31 09:06:09 +00:00
|
|
|
|
else{ /* symbol sync. achieved */
|
|
|
|
|
|
|
|
|
|
/* depending on the current symbol the sign of the angle difference
|
|
|
|
|
will change.
|
|
|
|
|
|
|
|
|
|
[n] [n-1]
|
|
|
|
|
135<EFBFBD> - 315<EFBFBD> < 0
|
|
|
|
|
315<EFBFBD> - 135 > 0
|
|
|
|
|
*/
|
1999-01-25 20:29:53 +00:00
|
|
|
|
if(priv->dem_angl_dif[priv->dem_index + priv->smpl_cnt] < 0)
|
|
|
|
|
priv->current_symbol = V29_symb_tbl[B9600];
|
|
|
|
|
else
|
|
|
|
|
priv->current_symbol = V29_symb_tbl[A9600];
|
|
|
|
|
priv->state = PHASEHUNT;
|
1999-01-31 09:06:09 +00:00
|
|
|
|
printf("Locked on symbol \n");
|
1999-01-25 20:29:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
short
|
|
|
|
|
PhaseHuntSeq2(V29demod_private * priv)
|
|
|
|
|
{
|
1999-02-21 12:19:37 +00:00
|
|
|
|
short e;
|
|
|
|
|
static int cnt = 0;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
1999-01-31 17:11:18 +00:00
|
|
|
|
/* adjust phi by the current phase difference */
|
|
|
|
|
priv->phi +=
|
|
|
|
|
priv->current_symbol.angl -
|
|
|
|
|
priv->dem_angl[priv->dem_index];
|
1999-02-21 12:19:37 +00:00
|
|
|
|
/*printf("0x%04X\n",priv->dem_re[priv->dem_index]);*/
|
1999-01-31 17:11:18 +00:00
|
|
|
|
/* toggle symbol */
|
1999-02-21 12:19:37 +00:00
|
|
|
|
if(priv->current_symbol.angl == DEG180){
|
|
|
|
|
if(cnt > 10){
|
|
|
|
|
e = priv->current_symbol.Re - priv->dem_re[priv->dem_index];
|
|
|
|
|
/*printf("%04X ",e);*/
|
|
|
|
|
e = (e * B) >> 18;
|
|
|
|
|
priv->agc_gain -= e;
|
|
|
|
|
printf("agc gain: %04X\n",priv->agc_gain);
|
|
|
|
|
}
|
|
|
|
|
cnt++;
|
1999-01-31 17:11:18 +00:00
|
|
|
|
priv->current_symbol = V29_symb_tbl[B9600];
|
1999-02-21 12:19:37 +00:00
|
|
|
|
}
|
1999-01-31 17:11:18 +00:00
|
|
|
|
else
|
|
|
|
|
priv->current_symbol = V29_symb_tbl[A9600];
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
short
|
|
|
|
|
DCD (short s, V29demod_private * priv)
|
|
|
|
|
{
|
|
|
|
|
int s_s;
|
1999-02-21 12:19:37 +00:00
|
|
|
|
|
1999-01-25 20:29:53 +00:00
|
|
|
|
/* Power Measurement s_s = a*(s[n] ) + s_s[n-1]*(1-a) */
|
|
|
|
|
|
|
|
|
|
s_s = (s * s) >> 15;
|
|
|
|
|
s_s = s_s - priv->power;
|
|
|
|
|
s_s = (s_s * priv->a) >> 15;
|
|
|
|
|
s_s = s_s + priv->power;
|
|
|
|
|
|
|
|
|
|
priv->power = s_s;
|
1999-02-21 12:19:37 +00:00
|
|
|
|
printf("power: 0x%04X\n",s_s);
|
1999-01-25 20:29:53 +00:00
|
|
|
|
|
1999-01-31 09:06:09 +00:00
|
|
|
|
if (s_s < L_MIN){
|
1999-01-25 20:29:53 +00:00
|
|
|
|
priv->state = NIL;
|
|
|
|
|
return s_s;
|
|
|
|
|
}
|
1999-01-31 09:06:09 +00:00
|
|
|
|
if (s_s > L_2){
|
1999-02-21 12:19:37 +00:00
|
|
|
|
if(priv->state == NIL) priv->state = ESTIMATEGAIN;
|
1999-01-25 20:29:53 +00:00
|
|
|
|
return s_s;
|
|
|
|
|
}
|
|
|
|
|
return s_s;
|
|
|
|
|
}
|