~ubuntu-branches/ubuntu/trusty/fldigi/trusty

« back to all changes in this revision

Viewing changes to src/dominoex/dominoex.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Joop Stakenborg
  • Date: 2008-11-17 19:40:43 UTC
  • mfrom: (1.1.6 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20081117194043-sfe108e41ppsyhxr
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
//
2
 
//    dominoex.cxx  --  DominoEX modem
 
2
// dominoex.cxx  --  DominoEX modem
3
3
//
4
 
//      Copyright (C) 2001, 2002, 2003
5
 
//      Tomi Manninen (oh2bns@sral.fi)
 
4
// Copyright (C) 2008
 
5
//              David Freese (w1hkj@w1hkj.com)
 
6
// based on code in gmfsk
6
7
//      Copyright (C) 2006
7
8
//      Hamish Moffatt (hamish@debian.org)
8
 
//      Copyright (C) 2006
9
 
//              David Freese (w1hkj@w1hkj.com)
10
9
// fldigi is free software; you can redistribute it and/or modify
11
10
// it under the terms of the GNU General Public License as published by
12
11
// the Free Software Foundation; either version 2 of the License, or
26
25
 
27
26
#include <stdlib.h>
28
27
 
29
 
#include <iostream>
 
28
#include <map>
30
29
 
31
30
#include "confdialog.h"
32
31
#include "status.h"
37
36
#include "filters.h"
38
37
#include "misc.h"
39
38
#include "sound.h"
 
39
#include "mfskvaricode.h"
 
40
#include "debug.h"
40
41
 
41
42
using namespace std;
42
43
 
43
 
#define AFC_COUNT       32
44
 
 
45
44
char dommsg[80];
 
45
static map<int, unsigned char> mupsksec2pri;
 
46
 
 
47
bool usingFEC = false;
46
48
 
47
49
void dominoex::tx_init(SoundBase *sc)
48
50
{
49
51
        scard = sc;
50
52
        txstate = TX_STATE_PREAMBLE;
51
53
        txprevtone = 0;
 
54
        Mu_bitstate = 0;
52
55
        counter = 0;
53
 
        phaseacc = 0.0;
 
56
        txphase = 0;
 
57
        
 
58
        strSecXmtText = progdefaults.secText;
 
59
        if (strSecXmtText.length() == 0)
 
60
                strSecXmtText = "fldigi "PACKAGE_VERSION" ";
 
61
 
54
62
        videoText();
55
63
}
56
64
 
58
66
{
59
67
        synccounter = 0;
60
68
        symcounter = 0;
 
69
        Mu_symcounter = 0;
61
70
        met1 = 0.0;
62
71
        met2 = 0.0;
63
72
        counter = 0;
64
 
        phaseacc = 0.0;
65
 
        freqerr = 0.0;
 
73
        phase[0] = 0.0;
 
74
        for (int i = 0; i < MAXFFTS; i++)
 
75
                phase[i+1] = 0.0;
66
76
        put_MODEstatus(mode);
67
77
        put_sec_char(0);
 
78
        syncfilter->reset();
 
79
 
 
80
        Mu_datashreg = 1;
 
81
        
 
82
        staticburst = false;
 
83
        set_AFCrange(0.1);
 
84
        set_AFCind(0.0);
 
85
}
 
86
 
 
87
void dominoex::reset_filters()
 
88
{
 
89
// fft filter at first IF frequency
 
90
        fft->create_filter( (FIRSTIF - 0.5 * progdefaults.DOMINOEX_BW * bandwidth) / samplerate,
 
91
                            (FIRSTIF + 0.5 * progdefaults.DOMINOEX_BW * bandwidth)/ samplerate );
 
92
 
 
93
        for (int i = 0; i < MAXFFTS; i++)
 
94
                if (binsfft[i]) delete binsfft[i];
 
95
                
 
96
        if (slowcpu) {
 
97
                extones = 4;
 
98
                paths = 3;
 
99
        } else {
 
100
                extones = NUMTONES / 2;
 
101
                paths = 5;
 
102
        }
 
103
        
 
104
        lotone = basetone - extones * doublespaced;
 
105
        hitone = basetone + NUMTONES * doublespaced + extones * doublespaced;
 
106
 
 
107
        numbins = hitone - lotone;
 
108
 
 
109
        for (int i = 0; i < paths; i++)//MAXFFTS; i++)
 
110
                binsfft[i] = new sfft (symlen, lotone, hitone);
 
111
 
 
112
        filter_reset = false;               
68
113
}
69
114
 
70
115
void dominoex::restart()
71
116
{
72
 
        double flo, fhi, bw, cf;
73
 
        
74
 
 
75
 
 
76
 
        bw = bandwidth * progdefaults.DOMINOEX_BW;
77
 
        cf = 1000.0 + bandwidth / 2.0;  // basetone is always 1000 Hz
78
 
                                        
79
 
 
80
 
        // mid frequency is always 1000 Hz + bandwidth / 2
81
 
        flo = (cf - bw/2) / samplerate;
82
 
        fhi = (cf + bw/2) / samplerate;
83
 
        if (filt)
84
 
                filt->init_bandpass (127, 1, flo, fhi);
85
 
 
86
 
        strSecXmtText = txtSecondary->value();
87
 
        if (strSecXmtText.length() == 0)
88
 
                strSecXmtText = "fldigi "PACKAGE_VERSION" ";
 
117
        filter_reset = true;
89
118
}
90
119
 
91
120
void dominoex::init()
92
121
{
 
122
        if (mupsksec2pri.empty())
 
123
                MuPsk_sec2pri_init();
 
124
 
93
125
        modem::init();
94
 
        restart();
 
126
//      reset_filters();
95
127
        rx_init();
96
 
//      digiscope->mode(Digiscope::SCOPE);
97
 
        digiscope->mode(Digiscope::DOMDATA);
 
128
 
 
129
        set_scope_mode(Digiscope::DOMDATA);
 
130
}
 
131
 
 
132
void dominoex::MuPsk_sec2pri_init(void)
 
133
{
 
134
        int chars[] = { 'A', 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, // À, Á, Â, Ã, Ä, Å
 
135
                        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, -1,  // à, á, â, ã, ä, å
 
136
                        'B', 0xdf, -1,                           // ß
 
137
                        'C', 0xc7, 0xe7, 0xa9, -1,               // Ç, ç, ©,
 
138
                        'D', 0xd0, 0xb0, -1,                     // Ð, °
 
139
                        'E', 0xc6, 0xe6, 0xc8, 0xc9, 0xca, 0xcb, // Æ, æ, È, É, Ê, Ë
 
140
                        0xe8, 0xe9, 0xea, 0xeb, -1,              // è, é, ê, ë
 
141
                        'F', 0x192, -1,                          // ƒ
 
142
                        'I', 0xcc, 0xcd, 0xce, 0xcf, 0xec, 0xed, // Ì, Í, Î, Ï, ì, í
 
143
                        0xee, 0xef, 0xa1, -1,                    // î, ï, ¡
 
144
                        'L', 0xa3, -1,                           // £
 
145
                        'N', 0xd1, 0xf1, -1,                     // Ñ, ñ
 
146
                        'O', 0xf4, 0xf6, 0xf2, 0xd6, 0xf3, 0xd3, // ô, ö, ò, Ö, ó, Ó
 
147
                        0xd4, 0xd2, 0xf5, 0xd5, -1,              // Ô, Ò, õ, Õ
 
148
                        'R', 0xae, -1,                           // ®
 
149
                        'U', 0xd9, 0xda, 0xdb, 0xdc, 0xf9, 0xfa, // Ù, Ú, Û, Ü, ù, ú
 
150
                        0xfb, 0xfc, -1,                          // û, ü
 
151
                        'X', 0xd7, -1,                           // ×
 
152
                        'Y', 0xff, 0xfd, 0xdd, -1,               // ÿ, ý, Ý
 
153
                        '0', 0xd8, -1,                           // Ø
 
154
                        '1', 0xb9, -1,                           // ¹
 
155
                        '2', 0xb2, -1,                           // ²
 
156
                        '3', 0xb3, -1,                           // ³
 
157
                        '?', 0xbf, -1,                           // ¿
 
158
                        '!', 0xa1, -1,                           // ¡
 
159
                        '<', 0xab, -1,                           // «
 
160
                        '>', 0xbb, -1,                           // »
 
161
                        '{', '(', -1,
 
162
                        '}', ')', -1,
 
163
                        '|', '\\'
 
164
        };
 
165
 
 
166
        int c = chars[0];
 
167
        for (size_t i = 1; i < sizeof(chars)/sizeof(*chars); i++) {
 
168
                if (chars[i] != -1)
 
169
                        mupsksec2pri[chars[i]] = c;
 
170
                else
 
171
                        c = chars[++i];
 
172
        }
98
173
}
99
174
 
100
175
dominoex::~dominoex()
101
176
{
102
 
        if (binsfft) delete binsfft;
103
177
        if (hilbert) delete hilbert;
 
178
        
 
179
        for (int i = 0; i < paths; i++) {//MAXFFTS; i++) {
 
180
                if (binsfft[i]) delete binsfft[i];
 
181
        }
 
182
 
 
183
        for (int i = 0; i < SCOPESIZE; i++) {
 
184
                if (vidfilter[i]) delete vidfilter[i];
 
185
        }
 
186
        if (syncfilter) delete syncfilter;
 
187
        
104
188
        if (pipe) delete [] pipe;
105
 
        if (filt) delete filt;
106
 
//      if (wfid) delete wfid;
 
189
        if (fft) delete fft;
 
190
        
 
191
        if (MuPskRxinlv) delete MuPskRxinlv;
 
192
        if (MuPskTxinlv) delete MuPskTxinlv;
 
193
        if (MuPskDec) delete MuPskDec;
 
194
        if (MuPskEnc) delete MuPskEnc;
 
195
        
107
196
}
108
197
 
109
198
dominoex::dominoex(trx_mode md)
110
199
{
111
 
        double cf, bw, flo, fhi;
 
200
        cap = CAP_REV;
112
201
 
113
 
        numtones = DOMNUMTONES;
114
202
        mode = md;
115
203
 
116
204
        switch (mode) {
 
205
// 11.025 kHz modes
 
206
        case MODE_DOMINOEX5:
 
207
                symlen = 2048;
 
208
                doublespaced = 2;
 
209
                samplerate = 11025;
 
210
                break;
 
211
 
 
212
        case MODE_DOMINOEX11:
 
213
                symlen = 1024;
 
214
                doublespaced = 1;
 
215
                samplerate = 11025;
 
216
                break;
 
217
 
 
218
        case MODE_DOMINOEX22:
 
219
                symlen = 512;
 
220
                doublespaced = 1;
 
221
                samplerate = 11025;
 
222
                break;
117
223
// 8kHz modes
118
224
        case MODE_DOMINOEX4:
119
225
                symlen = 2048;
120
 
                basetone = 256;         // 1000 Hz
121
 
                doublespaced = 1;
 
226
                doublespaced = 2;
122
227
                samplerate = 8000;
123
228
                break;
124
 
 
125
229
        case MODE_DOMINOEX8:
126
230
                symlen = 1024;
127
 
                basetone = 128;         // 1000 Hz
128
 
                doublespaced = 1;
 
231
                doublespaced = 2;
129
232
                samplerate = 8000;
130
233
                break;
131
 
 
132
234
        case MODE_DOMINOEX16:
133
235
                symlen = 512;
134
 
                basetone = 64;          // 1000 Hz
135
 
                doublespaced = 0;
 
236
                doublespaced = 1;
136
237
                samplerate = 8000;
137
238
                break;
138
 
 
139
 
// 11.025 kHz modes
140
 
        case MODE_DOMINOEX5:
141
 
                symlen = 2048;
142
 
                basetone = 186;         // 1001.3 Hz
143
 
                doublespaced = 1;
144
 
                samplerate = 11025;
145
 
                break;
146
 
 
147
 
        case MODE_DOMINOEX11:
148
 
                symlen = 1024;
149
 
                basetone = 93;          // 1001.3 Hz
150
 
                doublespaced = 0;
151
 
                samplerate = 11025;
152
 
                break;
153
 
 
154
 
        case MODE_DOMINOEX22:
155
 
                symlen = 512;
156
 
                basetone = 46;          // 990 Hz
157
 
                doublespaced = 0;
158
 
                samplerate = 11025;
159
 
                break;
160
 
        default:
161
 
        //      case MODE_DOMINOEX8:
162
 
                symlen = 1024;
163
 
                basetone = 128;         // 1000 Hz
164
 
                doublespaced = 1;
 
239
        default: // EX8
 
240
                symlen = 1024;
 
241
                doublespaced = 2;
165
242
                samplerate = 8000;
166
243
        }
167
244
 
168
 
        tonespacing = (double) (samplerate * ((doublespaced) ? 2 : 1)) / symlen;
169
 
 
170
 
        binsfft = new sfft(     symlen, 
171
 
                                                basetone - numtones*(doublespaced?2:1), 
172
 
                                                basetone + 2*numtones*(doublespaced ? 2 : 1) );
173
 
 
 
245
        tonespacing = 1.0 * samplerate * doublespaced / symlen;
 
246
 
 
247
        bandwidth = NUMTONES * tonespacing;
174
248
 
175
249
        hilbert = new C_FIR_filter();
176
250
        hilbert->init_hilbert(37, 1);
177
 
        afcfilt         = new Cmovavg(AFC_COUNT);
178
 
 
179
 
        pipe = new domrxpipe[2 * symlen];
180
 
        scopedata.alloc(2 * symlen);
181
 
        videodata.alloc(numtones * 6);
 
251
 
 
252
// fft filter at first if frequency
 
253
        fft = new fftfilt( (FIRSTIF - 0.5 * progdefaults.DOMINOEX_BW * bandwidth) / samplerate,
 
254
                           (FIRSTIF + 0.5 * progdefaults.DOMINOEX_BW * bandwidth)/ samplerate,
 
255
                           1024 );
 
256
 
 
257
        basetone = (int)floor(BASEFREQ * symlen / samplerate + 0.5);
 
258
 
 
259
        slowcpu = progdefaults.slowcpu;
 
260
        
 
261
        for (int i = 0; i < MAXFFTS; i++)
 
262
                binsfft[i] = 0;
 
263
                
 
264
        reset_filters();
 
265
        
 
266
        for (int i = 0; i < SCOPESIZE; i++)
 
267
                vidfilter[i] = new Cmovavg(16);
 
268
                        
 
269
        syncfilter = new Cmovavg(16);
 
270
 
 
271
        twosym = 2 * symlen;
 
272
        pipe = new domrxpipe[twosym];
 
273
        
 
274
        scopedata.alloc(SCOPESIZE);
 
275
        videodata.alloc(MAXFFTS * numbins);
 
276
 
182
277
        pipeptr = 0;
 
278
        
183
279
        symcounter = 0;
 
280
        Mu_symcounter = 0;
184
281
        metric = 0.0;
185
282
 
186
 
        bandwidth = (numtones - 1) * tonespacing;
187
 
        bw = bandwidth * progdefaults.DOMINOEX_BW;
188
 
        
189
 
        cf = 1000.0 + bandwidth / 2.0; // basetone is always 1000 Hz
190
 
 
191
 
        flo = (cf - bw/2) / samplerate;
192
 
        fhi = (cf + bw/2) / samplerate;
193
 
 
194
 
        filt = new C_FIR_filter();
195
 
        filt->init_bandpass (127, 1, flo, fhi);
196
 
 
197
283
        fragmentsize = symlen;
198
284
 
199
285
        s2n = 0.0;
200
 
//      wfid = new id(this);
201
286
 
202
287
        prev1symbol = prev2symbol = 0;
203
 
        prev1vector = prev2vector = complex(0.0, 0.0);
204
288
 
 
289
        MuPskEnc        = new encoder (K, POLY1, POLY2);
 
290
        MuPskDec        = new viterbi (K, POLY1, POLY2);
 
291
        MuPskDec->settraceback (45);
 
292
        MuPskDec->setchunksize (1);
 
293
        MuPskTxinlv = new interleave (-1, INTERLEAVE_FWD);
 
294
        MuPskRxinlv = new interleave (-1, INTERLEAVE_REV);
 
295
        Mu_bitstate = 0;
 
296
        Mu_symbolpair[0] = Mu_symbolpair[1] = 0;
 
297
        Mu_datashreg = 1;
205
298
        init();
206
299
}
207
300
 
208
301
//=====================================================================
209
302
// rx modules
210
 
 
211
 
complex dominoex::mixer(complex in, double f)
 
303
complex dominoex::mixer(int n, complex in)
212
304
{
213
305
        complex z;
214
 
// Basetone is always 1000 Hz
215
 
        f -= (1000.0 + bandwidth/2);
216
 
        z.re = cos(phaseacc);
217
 
        z.im = sin(phaseacc);
 
306
        double f;
 
307
 
 
308
// first IF mixer (n == 0) plus
 
309
// MAXFFTS mixers are supported each separated by tonespacing/paths
 
310
// n == 1, 2, 3, 4 ... MAXFFTS
 
311
        if (n == 0)
 
312
                f = frequency - FIRSTIF;
 
313
        else
 
314
                f = FIRSTIF - BASEFREQ - bandwidth / 2.0 + tonespacing * (1.0 * (n - 1) / paths );
 
315
        z.re = cos(phase[n]);
 
316
        z.im = sin(phase[n]);
218
317
        z = z * in;
219
 
        phaseacc -= twopi * f / samplerate;
220
 
        if (phaseacc > M_PI)
221
 
                phaseacc -= twopi;
222
 
        else if (phaseacc < M_PI)
223
 
                phaseacc += twopi;
 
318
        phase[n] -= TWOPI * f / samplerate;
 
319
        if (phase[n] > M_PI)
 
320
                phase[n] -= TWOPI;
 
321
        else if (phase[n] < M_PI)
 
322
                phase[n] += TWOPI;
224
323
        return z;
225
324
}
226
325
 
227
326
void dominoex::recvchar(int c)
228
327
{
229
 
        if (c == -1)
230
 
                return;
231
 
        if (c & 0x100)
232
 
                put_sec_char(c & 0xFF);
233
 
        else
234
 
                put_rx_char(c & 0xFF);
 
328
        if (!progStatus.sqlonoff || metric > progStatus.sldrSquelchValue) {
 
329
 
 
330
                if (c == -1)
 
331
                        return;
 
332
                if (c & 0x100)
 
333
                        put_sec_char(c & 0xFF);
 
334
                else
 
335
                        put_rx_char(c & 0xFF);
 
336
                }
235
337
}
236
338
 
237
 
void dominoex::decodesymbol(unsigned char curtone, unsigned char prevtone)
 
339
void dominoex::decodeDomino(int c)
238
340
{
239
 
        int c, sym, ch;
240
 
 
241
 
// Decode the IFK+ sequence, which results in a single nibble
242
 
        c = curtone - prevtone;
243
 
        if (reverse) c = -c;
244
 
        if (doublespaced) c /= 2;
245
 
        c -= 2;
246
 
        if (c < 0) c += numtones;
247
 
 
 
341
        int sym, ch;
248
342
//      If the new symbol is the start of a new character (MSB is low), complete the previous character
249
343
        if (!(c & 0x8)) {
250
344
                if (symcounter <= MAX_VARICODE_LEN) {
252
346
                        for (int i = 0; i < symcounter; i++)
253
347
                                sym |= symbolbuf[i] << (4 * i);
254
348
                        ch = dominoex_varidec(sym);
255
 
                        if (!progStatus.sqlonoff || metric > progStatus.sldrSquelchValue)               
256
 
                                recvchar(ch);
 
349
 
 
350
                                if (!progdefaults.DOMINOEX_FEC)
 
351
                                        if (!staticburst && !outofrange)
 
352
                                                recvchar(ch);
257
353
                }
258
354
                symcounter = 0;
259
355
        }
267
363
        symcounter++;
268
364
        if (symcounter > MAX_VARICODE_LEN + 1)
269
365
                symcounter = MAX_VARICODE_LEN + 1;
270
 
 
271
 
}
272
 
 
273
 
int dominoex::harddecode(complex *in)
 
366
}
 
367
 
 
368
void dominoex::decodesymbol()
 
369
{
 
370
        int c;
 
371
        double fdiff;
 
372
 
 
373
// Decode the IFK+ sequence, which results in a single nibble
 
374
 
 
375
        fdiff = currsymbol - prev1symbol;
 
376
        if (reverse) fdiff = -fdiff;
 
377
        fdiff /= doublespaced;
 
378
        fdiff /= paths;
 
379
        
 
380
//      if (fabs(fdiff) > 17) 
 
381
//              outofrange = true;
 
382
//      else
 
383
                outofrange = false;
 
384
        
 
385
        c = (int)floor(fdiff + .5) - 2;
 
386
        if (c < 0) c += NUMTONES;
 
387
 
 
388
        decodeDomino(c);
 
389
        decodeMuPskEX(c);
 
390
}
 
391
 
 
392
int dominoex::harddecode()
274
393
{
275
394
        double x, max = 0.0;
276
395
        int symbol = 0;
277
 
        
278
 
        for (int i = 0; i < numtones * 3*(doublespaced?2:1); i++) {
279
 
                x = in[i].mag();
280
 
                if (x > max) {
281
 
                        max = x;
282
 
                        symbol = i;
283
 
                }
284
 
        }
 
396
        double avg = 0.0;
 
397
        bool cwi[paths * numbins];
 
398
        double cwmag;
 
399
        
 
400
        for (int i = 0; i < paths * numbins; i++)
 
401
                avg += pipe[pipeptr].vector[i].mag();
 
402
        avg /= (paths * numbins);
 
403
                        
 
404
        if (avg < 1e-10) avg = 1e-10;
 
405
        
 
406
        int numtests = 10;
 
407
        int count = 0;
 
408
        for (int i = 0; i < paths * numbins; i++) {
 
409
                cwmag = 0.0;
 
410
                count = 0;
 
411
                for (int j = 1; j <= numtests; j++) {
 
412
                        int p = pipeptr - j;
 
413
                        if (p < 0) p += twosym;
 
414
                        cwmag = (pipe[j].vector[i].mag())/numtests;
 
415
                        if (cwmag >= 50.0 * (1.0 - progdefaults.ThorCWI) * avg) count++;
 
416
                }
 
417
                cwi[i] = (count == numtests);
 
418
        }
 
419
                                        
 
420
        for (int i = 0; i <  (paths * numbins); i++) {
 
421
                if (cwi[i] == false) {
 
422
                        x = pipe[pipeptr].vector[i].mag();
 
423
                        avg += x;
 
424
                        if (x > max) {
 
425
                                max = x;
 
426
                                symbol = i;
 
427
                        }
 
428
                }
 
429
        }
 
430
        avg /= (paths * numbins);
 
431
        staticburst = (max / avg < 1.2);
 
432
 
285
433
        return symbol;
286
434
}
287
435
 
288
 
void dominoex::update_syncscope(complex *bins)
 
436
void dominoex::update_syncscope()
289
437
{
 
438
 
290
439
        double max = 0, min = 1e6, range, mag;
291
 
        int numbins = numtones * 3 * (doublespaced ? 2 : 1);
 
440
 
292
441
// dom waterfall
293
 
        for (int i = 0; i < numbins; i++ ) {
294
 
                mag = bins[i].mag();
295
 
                if (max < mag) max = mag;
296
 
                if (min > mag) min = mag;
297
 
        }
298
 
        range = max - min;
299
 
        for (int i = 0; i < numbins; i++ ) {
300
 
                if (range > 2) {
301
 
                        mag = (bins[i].mag() - min) / range;
302
 
                        mag = 1 + log10(mag);
303
 
                        if (mag < 0) mag = 0;
304
 
                } else
305
 
                        mag = 0;
306
 
                videodata[i] = 255*mag;
307
 
        }
308
 
        if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
309
 
                set_video(videodata, numbins);
310
 
                videodata.next(); // change buffers
311
 
        }
312
 
 
313
 
// dom symbol synch data        
314
 
        memset(scopedata, 0, 2 * symlen * sizeof(double));
315
 
        if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue)
316
 
                for (int i = 0, j = 0; i < 2 * symlen; i++) {
317
 
                        j = (i + pipeptr) % (2 * symlen);
318
 
                        scopedata[i] = (pipe[j].vector[prev1symbol]).mag();
319
 
                }
320
 
        set_scope(scopedata, 2 * symlen);
321
 
        scopedata.next(); // change buffers
 
442
        memset(videodata, 0, (paths * numbins) * sizeof(double));
 
443
 
 
444
        if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
 
445
                for (int i = 0; i < (paths * numbins); i++ ) {
 
446
                        mag = pipe[pipeptr].vector[i].mag();
 
447
                        if (max < mag) max = mag;
 
448
                        if (min > mag) min = mag;
 
449
                }
 
450
                range = max - min;
 
451
                for (int i = 0; i < (paths * numbins); i++ ) {
 
452
                        if (range > 2) {
 
453
                                mag = (pipe[pipeptr].vector[i].mag() - min) / range + 0.0001;
 
454
                                mag = 1 + 2 * log10(mag);
 
455
                                if (mag < 0) mag = 0;
 
456
                        } else
 
457
                                mag = 0;
 
458
                        videodata[(i + paths * numbins / 2)/2] = 255*mag;
 
459
                }
 
460
        }
 
461
        set_video(videodata, (paths * numbins), false);
 
462
        videodata.next();
 
463
 
 
464
//      set_scope(scopedata, twosym);
 
465
// 64 data points is sufficient to show the signal progression through the
 
466
// convolution filter.
 
467
        memset(scopedata, 0, SCOPESIZE * sizeof(double));
 
468
        if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue) {
 
469
                for (unsigned int i = 0, j = 0; i < SCOPESIZE; i++) {
 
470
                        j = (pipeptr + i * twosym / SCOPESIZE + 1) % (twosym);
 
471
                        scopedata[i] = vidfilter[i]->run(pipe[j].vector[prev1symbol].mag());
 
472
                }
 
473
        }
 
474
        set_scope(scopedata, SCOPESIZE);
 
475
        scopedata.next();
322
476
}
323
477
 
324
478
void dominoex::synchronize()
325
479
{
326
 
        int syn = -1;
 
480
//      int syn = -1;
 
481
        double syn = -1;
327
482
        double val, max = 0.0;
328
483
 
 
484
        if (staticburst == true) return;
 
485
        
329
486
        if (currsymbol == prev1symbol)
330
487
                return;
331
488
        if (prev1symbol == prev2symbol)
332
489
                return;
333
490
 
334
 
        for (int i = 0, j = pipeptr; i < 2 * symlen; i++) {
 
491
        for (unsigned int i = 0, j = pipeptr; i < twosym; i++) {
335
492
                val = (pipe[j].vector[prev1symbol]).mag();
336
493
                if (val > max) {
337
494
                        max = val;
338
495
                        syn = i;
339
496
                }
340
 
                j = (j + 1) % (2 * symlen);
341
 
        }
342
 
        synccounter += (int) floor((syn - symlen) / numtones + 0.5);
343
 
}
344
 
 
345
 
void dominoex::reset_afc() {
346
 
        freqerr = 0.0;
347
 
        for (int i = 0; i < AFC_COUNT; i++) afcfilt->run(0.0);
348
 
        return;
349
 
}
350
 
 
351
 
void dominoex::afc()
352
 
{
353
 
        complex z;
354
 
        complex prevvector;
355
 
        double f, fsym, err;
356
 
        double ds = doublespaced ? 2 : 1;
357
 
 
358
 
        if (sigsearch) {
359
 
                reset_afc();
360
 
                sigsearch = 0;
361
 
        }
362
 
        
363
 
        if (pipeptr == 0)
364
 
                prevvector = pipe[2*symlen - 1].vector[currsymbol];
365
 
        else
366
 
                prevvector = pipe[pipeptr - 1].vector[currsymbol];
367
 
        
368
 
        z = prevvector % currvector;
369
 
 
370
 
        f = z.arg() * samplerate / twopi;
371
 
        fsym = (currsymbol / ds - numtones) * samplerate * ds / symlen;
372
 
        fsym += 1000;
373
 
        err = f - fsym;
374
 
 
375
 
//      freqerr = afcfilt->run(freqerr/numtones);
376
 
        freqerr = decayavg(freqerr, err, 64);
377
 
        
378
 
//      std::cout << currsymbol << ", " << freqerr << std::endl; 
379
 
        fflush(stdout);
380
 
        
381
 
        if (progStatus.afconoff && (metric > progStatus.sldrSquelchValue || progStatus.sqlonoff == false)) {
382
 
                set_freq(frequency + freqerr);
383
 
        }
384
 
}
385
 
 
386
 
void dominoex::eval_s2n(complex curr, complex n)
387
 
{
388
 
        sig = curr.mag(); // signal + noise energy
389
 
        noise = n.mag();// + 1e-10; // noise energy
390
 
        if (noise < 1e-20) noise = 1e-20;
391
 
        
392
 
        s2n = decayavg( s2n, sig / noise, 8);
393
 
 
394
 
        metric = 20*log10(s2n);
395
 
 
396
 
        display_metric(metric);
397
 
 
398
 
        snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", metric);
399
 
        put_Status1(dommsg);
400
 
 
 
497
                j = (j + 1) % twosym;
 
498
        }
 
499
        
 
500
        syn = syncfilter->run(syn);
 
501
 
 
502
        synccounter += (int) floor(1.0 * (syn - symlen) / NUMTONES + 0.5);
 
503
        
 
504
        set_AFCind(1.0 * (synccounter - symlen) / symlen);
 
505
 
 
506
        update_syncscope();
 
507
}
 
508
 
 
509
 
 
510
void dominoex::eval_s2n()
 
511
{
 
512
        if (currsymbol != prev1symbol && prev1symbol != prev2symbol) {
 
513
                sig = pipe[pipeptr].vector[currsymbol].mag();
 
514
                noise = 0.0;
 
515
                for (int i = 0; i < paths * numbins; i++) {
 
516
                        if (i != currsymbol)
 
517
                                noise += pipe[pipeptr].vector[i].mag();
 
518
                }       
 
519
                noise /= (paths * numbins - 1);
 
520
        
 
521
                s2n = decayavg( s2n, sig / noise, 32);
 
522
 
 
523
                metric = 3*(20*log10(s2n) - 9.0);
 
524
 
 
525
                display_metric(metric);
 
526
 
 
527
                snprintf(dommsg, sizeof(dommsg), "s/n %3.0f dB", metric / 3.0 - 2.0);
 
528
                put_Status1(dommsg);
 
529
        }
401
530
}
402
531
 
403
532
int dominoex::rx_process(const double *buf, int len)
404
533
{
405
 
        complex z, *bins, noise;
406
 
 
407
 
        while (len-- > 0) {
408
 
// create analytic signal...shift in frequency to base band & bandpass filter
409
 
                z.re = z.im = *buf++;
410
 
                hilbert->run(z, z);
411
 
                z = mixer(z, frequency);
412
 
                filt->run(z, z);
413
 
                
414
 
// feed it to the sliding FFT
415
 
                bins = binsfft->run(z);
416
 
 
417
 
// copy current vector to the pipe
418
 
                for (int i = 0; i < numtones*3*(doublespaced?2:1); i++)
419
 
                        pipe[pipeptr].vector[i] = bins[i];
420
 
 
421
 
                if (--synccounter <= 0) {
422
 
                        synccounter = symlen;
423
 
                        currsymbol = harddecode(bins);
424
 
                        currvector = bins[currsymbol];
425
 
// decode symbol
426
 
            decodesymbol(currsymbol, prev1symbol);
427
 
// update the scope
428
 
                        update_syncscope(bins);
429
 
// symbol sync
430
 
                        synchronize();
431
 
// frequency tracking
432
 
                        afc();
433
 
                        eval_s2n(currvector, bins[(numtones + 2) * (doublespaced ? 2 : 1)]);
434
 
 
435
 
                        prev2symbol = prev1symbol;
436
 
                        prev2vector = prev1vector;
437
 
                        prev1symbol = currsymbol;
438
 
                        prev1vector = currvector;
439
 
                }
440
 
                pipeptr = (pipeptr + 1) % (2 * symlen);
441
 
        }
 
534
        complex zref,  z, *zp, *bins = 0;
 
535
        complex zarray[1];
 
536
        int n;
 
537
 
 
538
        if (filter_reset) reset_filters();
 
539
 
 
540
        if (slowcpu != progdefaults.slowcpu) {
 
541
                slowcpu = progdefaults.slowcpu;
 
542
                reset_filters();
 
543
        }
 
544
        
 
545
        while (len) {
 
546
// create analytic signal at first IF
 
547
                zref.re = zref.im = *buf++;
 
548
                hilbert->run(zref, zref);
 
549
                zref = mixer(0, zref);
 
550
                
 
551
                if (progdefaults.DOMINOEX_FILTER) {
 
552
// filter using fft convolution
 
553
                        n = fft->run(zref, &zp);
 
554
                } else {
 
555
                        zarray[0] = zref;
 
556
                        zp = zarray;
 
557
                        n = 1;
 
558
                }
 
559
                
 
560
                if (n) {
 
561
                        for (int i = 0; i < n; i++) {
 
562
// process MAXFFTS sets of sliding FFTs spaced at 1/MAXFFTS bin intervals each of which
 
563
// is a matched filter for the current symbol length
 
564
                                for (int j = 0; j < paths; j++) {
 
565
// shift in frequency to base band for the sliding DFTs
 
566
                                        z = mixer(j + 1, zp[i]);
 
567
                                        bins = binsfft[j]->run(z);
 
568
// copy current vector to the pipe interleaving the FFT vectors
 
569
                                        for (int k = 0; k < numbins; k++) {
 
570
                                                pipe[pipeptr].vector[j + paths * k] = bins[k];
 
571
                                        }
 
572
                                }
 
573
                                if (--synccounter <= 0) {
 
574
                                        synccounter = symlen;
 
575
                                        currsymbol = harddecode();
 
576
                            decodesymbol();
 
577
                                        synchronize();
 
578
//                                      update_syncscope();
 
579
                                        eval_s2n();
 
580
                                        prev2symbol = prev1symbol;
 
581
                                        prev1symbol = currsymbol;
 
582
                                }
 
583
                                pipeptr++;
 
584
                                if (pipeptr >= twosym)
 
585
                                        pipeptr = 0;
 
586
                        }
 
587
                }
 
588
                --len;
 
589
        }
 
590
                        
442
591
        return 0;
443
592
}
444
593
 
455
604
        return chr;
456
605
}
457
606
 
 
607
void dominoex::sendtone(int tone, int duration)
 
608
{
 
609
        double f, phaseincr;
 
610
        f = (tone + 0.5) * tonespacing + get_txfreq_woffset() - bandwidth / 2.0;
 
611
        phaseincr = TWOPI * f / samplerate;
 
612
        for (int j = 0; j < duration; j++) {
 
613
                for (int i = 0; i < symlen; i++) {
 
614
                        outbuf[i] = cos(txphase);
 
615
                        txphase -= phaseincr;
 
616
                        if (txphase > M_PI)
 
617
                                txphase -= TWOPI;
 
618
                        else if (txphase < M_PI)
 
619
                                txphase += TWOPI;
 
620
                }
 
621
                ModulateXmtr(outbuf, symlen);
 
622
        }
 
623
}
 
624
 
458
625
void dominoex::sendsymbol(int sym)
459
626
{
460
627
//static int first = 0;
461
628
        complex z;
462
629
    int tone;
463
 
        double f, phaseincr;
464
630
        
465
 
        tone = (txprevtone + 2 + sym) % numtones;
 
631
        tone = (txprevtone + 2 + sym) % NUMTONES;
466
632
    txprevtone = tone;
467
633
        if (reverse)
468
 
                tone = (numtones - 1) - tone;
469
 
 
470
 
        f = tone * tonespacing + get_txfreq_woffset() - bandwidth / 2;
471
 
        
472
 
        phaseincr = twopi * f / samplerate;
473
 
        
474
 
        for (int i = 0; i < symlen; i++) {
475
 
                outbuf[i] = cos(phaseacc);
476
 
                phaseacc -= phaseincr;
477
 
                if (phaseacc > M_PI)
478
 
                        phaseacc -= twopi;
479
 
                else if (phaseacc < M_PI)
480
 
                        phaseacc += twopi;
481
 
        }
482
 
        ModulateXmtr(outbuf, symlen);
483
 
 
 
634
                tone = (NUMTONES - 1) - tone;
 
635
        sendtone(tone, 1);
484
636
}
485
637
 
486
 
 
487
638
void dominoex::sendchar(unsigned char c, int secondary)
488
639
{
489
 
        unsigned char *code = dominoex_varienc(c, secondary);
490
 
 
491
 
    sendsymbol(code[0]);
 
640
        if (progdefaults.DOMINOEX_FEC) 
 
641
                sendMuPskEX(c, secondary);
 
642
        else {
 
643
                unsigned char *code = dominoex_varienc(c, secondary);
 
644
        sendsymbol(code[0]);
492
645
// Continuation nibbles all have the MSB set
493
 
    for (int sym = 1; sym < 3; sym++) {
494
 
        if (code[sym] & 0x8) 
495
 
            sendsymbol(code[sym]);
496
 
        else
497
 
            break;
498
 
    }
 
646
            for (int sym = 1; sym < 3; sym++) {
 
647
            if (code[sym] & 0x8) 
 
648
                    sendsymbol(code[sym]);
 
649
                else
 
650
                break;
 
651
        }
 
652
        }
499
653
        if (!secondary)
500
654
                put_echo_char(c);
501
655
}
513
667
 
514
668
void dominoex::flushtx()
515
669
{
 
670
//      if (progdefaults.DOMINOEX_FEC)
 
671
//              MuPskFlushTx();
 
672
//      else {
516
673
// flush the varicode decoder at the receiver end
517
 
    for (int i = 0; i < 4; i++)
518
 
        sendidle();
 
674
            for (int i = 0; i < 4; i++)
 
675
            sendidle();
 
676
//      }
519
677
}
520
678
 
521
679
int dominoex::tx_process()
524
682
 
525
683
        switch (txstate) {
526
684
        case TX_STATE_PREAMBLE:
 
685
                if (progdefaults.DOMINOEX_FEC)
 
686
                        MuPskClearbits();
527
687
        sendidle();
528
688
                txstate = TX_STATE_START;
529
689
                break;
557
717
        }
558
718
        return 0;
559
719
}
 
720
 
 
721
//=============================================================================
 
722
// MultiPsk compatible FEC methods
 
723
//=============================================================================
 
724
 
 
725
//=============================================================================
 
726
// Varicode support methods
 
727
// MultiPsk varicode is based on a modified MFSK varicode table in which
 
728
// Character substition is used for secondary text.  The resulting table does
 
729
// NOT contain the full ASCII character set as the primary.  Many of the
 
730
// control codes and characters above 0x80 are lost.
 
731
//=============================================================================
 
732
 
 
733
// Convert from Secondary to Primary character
 
734
 
 
735
unsigned char dominoex::MuPskSec2Pri(int c)
 
736
{
 
737
        if (c >= 'a' && c <= 'z') c -= 32;
 
738
 
 
739
        c = mupsksec2pri.find(c) != mupsksec2pri.end() ? mupsksec2pri[c] : c;
 
740
 
 
741
        if (c >= 'A' && c <= 'Z') c = c - 'A' + 127;
 
742
        else if (c >= '0' && c <= '9') c = c - '0' + 14;
 
743
        else if (c >= ' ' && c <= '"') c = c - ' ' + 1;
 
744
        else if (c == '_') c = 4;
 
745
        else if (c >= '$' && c <= '&') c = c - '$' + 5;
 
746
        else if (c >= '\'' && c <= '*') c = c - '\'' + 9;
 
747
        else if (c >= '+' && c <= '/') c = c - '+' + 24;
 
748
        else if (c >= ':' && c <= '<') c = c - ':' + 29;
 
749
        else if (c >= '=' && c <= '@') c = c - '=' + 153;
 
750
        else if (c >= '[' && c <= ']') c = c - '[' + 157;
 
751
        else c = '_';
 
752
        
 
753
        return c;
 
754
}
 
755
 
 
756
// Convert Primary to Split Primary / Secondary character
 
757
 
 
758
unsigned int dominoex::MuPskPriSecChar(unsigned int c)
 
759
{
 
760
        if (c >= 127 && c < 153) c += ('A' - 127) + 0x100;
 
761
        else if (c >=14 && c < 24) c += ('0' - 14) + 0x100;
 
762
        else if (c >= 1 && c < 4) c += (' ' - 1) + 0x100;
 
763
        else if (c == 4) c = '_' + 0x100;
 
764
        else if (c >= 5 && c < 8) c += ('$' - 5) + 0x100;
 
765
        else if (c >= 9 && c < 13) c += ('\'' - 9) + 0x100;
 
766
        else if (c >= 24 && c < 29) c += ('+' - 24) + 0x100;
 
767
        else if (c >= 29 && c < 32) c += (':' - 29) + 0x100;
 
768
        else if (c >= 153 && c < 157) c += ('=' - 153) + 0x100;
 
769
        else if (c >= 157 && c < 160) c += ('[' - 157) + 0x100;
 
770
        return c;
 
771
}
 
772
 
 
773
//=============================================================================
 
774
// Receive
 
775
//=============================================================================
 
776
 
 
777
void dominoex::decodeMuPskSymbol(unsigned char symbol)
 
778
{
 
779
        int c, ch, met;
 
780
 
 
781
        Mu_symbolpair[0] = Mu_symbolpair[1];
 
782
        Mu_symbolpair[1] = symbol;
 
783
 
 
784
        Mu_symcounter = Mu_symcounter ? 0 : 1;
 
785
        
 
786
        if (Mu_symcounter) return;
 
787
 
 
788
        c = MuPskDec->decode (Mu_symbolpair, &met);
 
789
 
 
790
        if (c == -1)
 
791
                return;
 
792
 
 
793
        if (progStatus.sqlonoff && metric < progStatus.sldrSquelchValue)
 
794
                return;
 
795
 
 
796
        Mu_datashreg = (Mu_datashreg << 1) | !!c;
 
797
        if ((Mu_datashreg & 7) == 1) {
 
798
                ch = varidec(Mu_datashreg >> 1);
 
799
                if (progdefaults.DOMINOEX_FEC)
 
800
                        recvchar(MuPskPriSecChar(ch));
 
801
                Mu_datashreg = 1;
 
802
        }
 
803
}
 
804
 
 
805
void dominoex::decodeMuPskEX(int ch)
 
806
{
 
807
        unsigned char symbols[4];
 
808
        int c = ch;
 
809
        
 
810
        for (int i = 0; i < 4; i++) {
 
811
                if ((c & 1) == 1) symbols[3-i] = 255;
 
812
                else symbols[3-i] = 1;//-255;
 
813
                c = c / 2;
 
814
        }
 
815
        if (staticburst == true || outofrange == true)
 
816
                symbols[3] = symbols[2] = symbols[1] = symbols[0] = 0;
 
817
                
 
818
        MuPskRxinlv->symbols(symbols);
 
819
 
 
820
        for (int i = 0; i < 4; i++) decodeMuPskSymbol(symbols[i]);
 
821
 
 
822
}
 
823
 
 
824
//=============================================================================
 
825
// Transmit
 
826
//=============================================================================
 
827
 
 
828
void dominoex::MuPskFlushTx()
 
829
{
 
830
// flush the varicode decoder at the other end
 
831
// flush the convolutional encoder and interleaver
 
832
        sendsymbol(1);
 
833
        for (int i = 0; i < 107; i++)
 
834
                sendsymbol(0);
 
835
        Mu_bitstate = 0;
 
836
}
 
837
 
 
838
void dominoex::MuPskClearbits()
 
839
{
 
840
        int data = MuPskEnc->encode(0);
 
841
        for (int k = 0; k < 100; k++) {
 
842
                for (int i = 0; i < 2; i++) {
 
843
                        bitshreg = (bitshreg << 1) | ((data >> i) & 1);
 
844
                        Mu_bitstate++;
 
845
 
 
846
                        if (Mu_bitstate == 4) {
 
847
                                MuPskTxinlv->bits(&bitshreg);
 
848
                                Mu_bitstate = 0;
 
849
                                bitshreg = 0;
 
850
                        }
 
851
                }
 
852
        }
 
853
}
 
854
 
 
855
// Send MultiPsk FEC varicode with minimalist interleaver
 
856
 
 
857
void dominoex::sendMuPskEX(unsigned char c, int secondary)
 
858
{
 
859
        const char *code;
 
860
        if (secondary == 1) 
 
861
                c = MuPskSec2Pri(c);
 
862
        else {
 
863
                if (c == 10) 
 
864
                        return;
 
865
                if ( (c >= 1 && c <= 7) || (c >= 9 && c <= 12) || (c >= 14 && c <= 31) ||
 
866
                     (c >= 127 && c <= 159))
 
867
                   c = '_';
 
868
        }
 
869
        code = varienc(c);
 
870
        // if (secondary == 0)
 
871
        //      LOG_DEBUG("char=%hhu, code=\"%s\"", c, code);
 
872
        while (*code) {
 
873
                int data = MuPskEnc->encode(*code++ - '0');
 
874
                // LOG_DEBUG("data=%d", data;
 
875
                for (int i = 0; i < 2; i++) {
 
876
                        bitshreg = (bitshreg << 1) | ((data >> i) & 1);
 
877
                        Mu_bitstate++;
 
878
                        if (Mu_bitstate == 4) {
 
879
 
 
880
                                MuPskTxinlv->bits(&bitshreg);
 
881
 
 
882
                                // LOG_DEBUG("bitshreg=%d", bitshreg);
 
883
 
 
884
                                sendsymbol(bitshreg);
 
885
 
 
886
                                // decodeMuPskEX(bitshreg);
 
887
 
 
888
                                Mu_bitstate = 0;
 
889
                                bitshreg = 0;
 
890
                        }
 
891
                }
 
892
        }
 
893
}