/*****************************************************************************/ /* * hbgdemod.c -- Linux soundcard HBG receiver, demodulator code. * * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) * Swiss Federal Institute of Technology (ETH), Electronics Lab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * */ /*****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "dcf77.h" #include "xgintf.h" /* --------------------------------------------------------------------- */ #define INF_N 96 static struct hbg_state { unsigned int sample_rate; struct { int inf_i[INF_N]; int inf_q[INF_N]; unsigned int inf_ptr; unsigned int ph_car; int car_fcorr; } f; struct { unsigned int car_inc, sec_inc; union { struct { } pn; struct { unsigned int ampl; unsigned int amphist; unsigned int state; unsigned int decay_cnt; } a; } d; int sec_ph; int sec_fcorr; } d; struct { unsigned long long dbits; unsigned int dcnt; unsigned int dhist; } t; } d; /* --------------------------------------------------------------------- */ static void hbg_init(unsigned int sample_rate) { memset(&d, 0, sizeof(d)); d.sample_rate = sample_rate; d.d.car_inc = 0x1000000ULL * CARRIER_FREQ / sample_rate; d.d.sec_inc = 0x40000000UL / sample_rate; } /* --------------------------------------------------------------------- */ extern __inline__ void decode_ampl_bit(unsigned int bit, unsigned int samples) { vlprintf(2, "Decode Bit: %u Cnt: %u\n", bit, d.t.dcnt); if (bit == 0) { if (d.t.dcnt >= 59) time_decode(d.t.dbits, samples); d.t.dbits = 0; d.t.dcnt = 0; return; } if (d.t.dcnt >= 60) return; if (bit == 2) d.t.dbits |= 1ULL << d.t.dcnt; d.t.dcnt++; } /* --------------------------------------------------------------------- */ extern __inline__ void hbg_process_ampl(int si, unsigned int samples) { static int rodcnt = 0; char* rod = "|/-\\ "; if ((++d.d.d.a.decay_cnt) >= 400) { d.d.d.a.decay_cnt = 0; d.d.d.a.ampl = (d.d.d.a.ampl * 4055) >> 12; } if (d.d.sec_ph >= 0x40000000) { d.d.sec_ph &= 0x3fffffff; d.d.sec_ph += d.d.sec_fcorr; d.d.d.a.state = 0; } if (si > 0 && si > d.d.d.a.ampl) d.d.d.a.ampl += (si - d.d.d.a.ampl) >> 4; d.d.d.a.amphist = (d.d.d.a.amphist << 1) | (d.d.d.a.amphist & 1); if (si > (d.d.d.a.ampl/2)) d.d.d.a.amphist |= 1; else if (si < (d.d.d.a.ampl/8)) d.d.d.a.amphist &= ~1; d.d.d.a.amphist &= 0xffffffffu; if (d.d.d.a.amphist == 0xffff0000u) { if (d.d.sec_ph >= 0x40000000/100*35 && d.d.sec_ph <= 0x40000000/100*45) { /* minute mark */ d.d.d.a.state = 4; } else { vlprintf(2, "second tick at: %08x\n", d.d.sec_ph); if (verboselevel < 2) { printf("\t\t\t\t\t\t\t\t%c\r", rod[rodcnt]); fflush(stdout); // without this, printf does not printf!! rodcnt++; if (rodcnt > 3) rodcnt = 0; } if (((d.d.sec_ph - (0x40000000 / SAMPLE_RATE * 16)) & 0x3fffffff) < 0x20000000) { d.d.sec_ph -= 0x400000; d.d.sec_fcorr -= 0x10; } else { d.d.sec_ph += 0x400000; d.d.sec_fcorr += 0x10; } } } if (!d.d.d.a.state && (d.d.d.a.amphist & 3) == 1) { if (d.d.sec_ph >= 0x40000000/100*5 && d.d.sec_ph <= 0x40000000/100*15) d.d.d.a.state = 1; else if (d.d.sec_ph >= 0x40000000/100*15 && d.d.sec_ph <= 0x40000000/100*25) d.d.d.a.state = 2; } if (d.d.d.a.state < 4 && d.d.sec_ph >= 0x40000000/100*50) { decode_ampl_bit(d.d.d.a.state, samples); d.d.d.a.state = 4; } } /* --------------------------------------------------------------------- */ static void hbg_demod(const short *s, unsigned int n) { unsigned int samples; int si, sq; unsigned int u; int i; for (samples = 0; samples < n; samples++, s++) { d.f.inf_i[d.f.inf_ptr] = (COS(d.f.ph_car) * (*s)) >> 15; d.f.inf_q[d.f.inf_ptr] = (SIN(d.f.ph_car) * (*s)) >> 15; d.f.inf_ptr = (d.f.inf_ptr + 1) % INF_N; for (si = sq = u = 0; u < INF_N; u++) { si += d.f.inf_i[u]; sq += d.f.inf_q[u]; } si >>= 4; sq >>= 4; if (abs(sq) > (abs(si) >> 8)) { if (sq > 0) { d.f.ph_car -= 8192; d.f.car_fcorr -= 1; } else { d.f.ph_car += 8192; d.f.car_fcorr += 1; } } d.f.ph_car = (d.f.ph_car + d.d.car_inc + d.f.car_fcorr) & 0xffffffu; #if 0 xg_val(0, si, "I"); xg_val(1, sq, "Q"); xg_val(2, d.d.d.a.ampl, "Ampl"); xg_next(8192, "HBG phase recovery"); #endif hbg_process_ampl(si, samples); d.d.sec_ph += d.d.sec_inc; if (d.d.sec_ph >= 0x40000000) { vlprintf(2, "Carrier frequency offset: %6.3fHz Sec freq offset: %6.1fms/s\n", d.f.car_fcorr * ((float)d.sample_rate / (float)0x1000000), d.d.sec_fcorr * (1000.0 / 0x40000000)); } } i = d.d.car_inc >> 8; if (abs(d.f.car_fcorr) >= i) { if (d.f.car_fcorr > 0) d.f.car_fcorr = i; else d.f.car_fcorr = -i; } if (abs(d.d.sec_fcorr) > 0x100000) { if (d.d.sec_fcorr > 0) d.d.sec_fcorr = 0x100000; else d.d.sec_fcorr = -0x100000; } } /* --------------------------------------------------------------------- */ const struct demodulator hbg_demodulator = { "HBG demodulator ampl", hbg_init, hbg_demod }; /* --------------------------------------------------------------------- */