1 // ----------------------------------------------------------------------------
2 // mt63.cxx -- MT63 modem for fldigi
3 //
4 // Copyright (C) 1999-2004 Pawel Jalocha, SP9VRC
5 // Copyright (c) 2007-2011 Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi.
8 //
9 // Fldigi is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // Fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22
23 #include <config.h>
24
25 #include "configuration.h"
26 #include "fl_digi.h"
27 #include "status.h"
28 #include "mt63.h"
29
30 //------------------------------------------------------------------------------
31 #include "threads.h"
32
33 static pthread_mutex_t mt63_mutex = PTHREAD_MUTEX_INITIALIZER;
34 //------------------------------------------------------------------------------
35
36 using namespace std;
37 bool startflag = true;
38
tx_init()39 void mt63::tx_init()
40 {
41 guard_lock dsp_lock(&mt63_mutex);
42
43 Tx->Preset(get_txfreq_woffset(), (int)bandwidth, Interleave == 64 ? 1 : 0);
44 flush = Tx->DataInterleave;
45 videoText();
46 startflag = true;
47 }
48
rx_init()49 void mt63::rx_init()
50 {
51 guard_lock dsp_lock(&mt63_mutex);
52
53 Rx->Preset( frequency,
54 (int)bandwidth,
55 Interleave == 64 ? 1 : 0,
56 long_integral ? 32 : 16 );
57 InpLevel->Preset(64.0, 0.75);
58 escape = 0;
59 }
60
tx_process()61 int mt63::tx_process()
62 {
63 rx_flush();
64 // do not put above rx_flush()
65
66 modem::tx_process();
67
68 guard_lock dsp_lock(&mt63_mutex);
69
70 int c;
71
72 if (startflag == true) {
73 startflag = false;
74 maxval = 0.0;
75 if (progdefaults.mt63_usetones) {
76 double w1 = 2.0 * M_PI * (get_txfreq_woffset() - bandwidth / 2.0) / samplerate;
77 double w2 = 2.0 * M_PI * (get_txfreq_woffset() + 31.0 * bandwidth / 64.0) / samplerate;
78 double phi1 = 0.0;
79 double phi2 = 0.0;
80 double buff[512];
81 int numsmpls = samplerate * progdefaults.mt63_tone_duration / 512;
82 for (int i = 0; i < numsmpls; i++) {
83 for (int j = 0; j < 512; j++) {
84 buff[j] = TONE_AMP * (progdefaults.mt63_twotones ? 0.5 : 1.0) * cos(phi1) +
85 TONE_AMP * (progdefaults.mt63_twotones ? 0.5 : 0.0) * cos(phi2);
86 phi1 += w1;
87 phi2 += w2;
88 if (i == 0) buff[j] *= (1.0 - exp(-1.0 * j / 40.0));
89 if (i == progdefaults.mt63_tone_duration - 1)
90 buff[j] *= (1.0 - exp(-1.0 * (samplerate - j) / 40.0));
91 }
92 Fl::awake();
93 ModulateXmtr(buff, 512);
94 }
95 }
96 for (int i = 0; i < Tx->DataInterleave; i++) {
97 Tx->SendChar(0);
98 Fl::awake();
99 }
100 }
101
102 c = get_tx_char();
103 if (c == GET_TX_CHAR_ETX) {
104 stopflag = true;
105 flush = Tx->DataInterleave;
106 }
107
108 if (c == GET_TX_CHAR_NODATA || stopflag == true) c = 0;
109
110 if (stopflag) {
111 stopflag = false;
112 while (--flush) {
113 Tx->SendChar(0);
114 double buff[Tx->Comb.Output.Len];
115 for (int i = 0; i < Tx->Comb.Output.Len; i++)
116 if (fabs(Tx->Comb.Output.Data[i]) > maxval)
117 maxval = fabs(Tx->Comb.Output.Data[i]);
118 for (int i = 0; i < Tx->Comb.Output.Len; i++)
119 buff[i] = Tx->Comb.Output.Data[i] /= maxval;
120 ModulateXmtr(buff,Tx->Comb.Output.Len);
121 }
122 Tx->SendJam();
123 maxval = 0.0;
124 double buff[Tx->Comb.Output.Len];
125 for (int i = 0; i < Tx->Comb.Output.Len; i++)
126 if (fabs(Tx->Comb.Output.Data[i]) > maxval)
127 maxval = fabs(Tx->Comb.Output.Data[i]);
128 for (int i = 0; i < Tx->Comb.Output.Len; i++)
129 buff[i] = Tx->Comb.Output.Data[i] * 1.0 / maxval;
130 ModulateXmtr(buff,Tx->Comb.Output.Len);
131 return -1; /* we're done */
132 }
133
134 if (c > 255 || (!progdefaults.mt63_8bit && c > 127))
135 c = '.';
136
137 int sendc = c;
138
139 if (sendc > 127) {
140 sendc &= 127;
141 Tx->SendChar(127);
142 double buff[Tx->Comb.Output.Len];
143 for (int i = 0; i < Tx->Comb.Output.Len; i++)
144 if (fabs(Tx->Comb.Output.Data[i]) > maxval)
145 maxval = fabs(Tx->Comb.Output.Data[i]);
146 for (int i = 0; i < Tx->Comb.Output.Len; i++)
147 buff[i] = Tx->Comb.Output.Data[i] * 1.0 / maxval;
148 ModulateXmtr(buff,Tx->Comb.Output.Len);
149 }
150
151 Tx->SendChar(sendc);
152 double buff[Tx->Comb.Output.Len];
153 int len = Tx->Comb.Output.Len;
154 for (int i = 0; i < len; i++) {
155 buff[i] = Tx->Comb.Output.Data[i];
156 if (maxval < fabs(buff[i])) maxval = fabs(buff[i]);
157 }
158 for (int i = 0; i < len; i++) {
159 buff[i] *= 1.0 / maxval;
160 }
161 ModulateXmtr(buff,len);
162
163 put_echo_char(c);
164
165 return 0;
166 }
167
rx_process(const double * buf,int len)168 int mt63::rx_process(const double *buf, int len)
169 {
170 double snr;
171 unsigned int c;
172 int i;
173 static char msg1[20];
174 static char msg2[20];
175 double f_offset;
176
177 if (long_integral != progdefaults.mt63_rx_integration) {
178 long_integral = progdefaults.mt63_rx_integration;
179 restart();
180 }
181
182 if (InpBuff->EnsureSpace(len) == -1) {
183 fprintf(stderr, "mt63_rxprocess: buffer error\n");
184 return -1;
185 }
186
187 for (i = 0; i < len; i++)
188 InpBuff->Data[i] = buf[i];
189
190 { // critical section
191 guard_lock dsp_lock(&mt63_mutex);
192
193 InpBuff->Len = len;
194 InpLevel->Process(InpBuff);
195
196 Rx->Process(InpBuff);
197
198 snr = Rx->FEC_SNR();
199 if (progStatus.sqlonoff && snr < progStatus.sldrSquelchValue) {
200 put_Status1("");
201 put_Status2("");
202 display_metric(0);
203 return 0;
204 }
205
206 for (i = 0; i < Rx->Output.Len; i++) {
207 c = Rx->Output.Data[i];
208 if (!progdefaults.mt63_8bit) {
209 put_rx_char(c);
210 continue;
211 }
212 if ((c < 8) && (escape == 0))
213 continue;
214 if (c == 127) {
215 escape = 1;
216 continue;
217 }
218 if (escape) {
219 c += 128;
220 escape = 0;
221 }
222 put_rx_char(c);
223 }
224
225 f_offset = Rx->TotalFreqOffset();
226
227 } // end critical section
228
229 if (snr > 99.9) snr = 99.9;
230
231 display_metric(snr);
232
233 double s2n = 10.0*log10( snr == 0 ? 0.001 : snr);
234 snprintf(msg1, sizeof(msg1), "s/n %2d dB", (int)(floor(s2n)));
235 put_Status1(msg1);
236
237 snprintf(msg2, sizeof(msg2), "f/o %+4.1f Hz", f_offset);
238 put_Status2(msg2, 5, STATUS_CLEAR);
239
240 flushbuffer = true;
241
242 return 0;
243 }
244
rx_flush()245 void mt63::rx_flush()
246 {
247 guard_lock dsp_lock(&mt63_mutex);
248
249 unsigned int c;
250 int len = 512;
251 int dlen = 0;
252
253 if (!flushbuffer) return;
254
255 if (emptyBuff->EnsureSpace(len) == -1) {
256 flushbuffer = false;
257 return;
258 }
259
260 for (int j = 0; j < len; j++)
261 emptyBuff->Data[j] = 0.0;
262 emptyBuff->Len = len;
263 InpLevel->Process(emptyBuff);
264 Rx->Process(emptyBuff);
265 dlen = Rx->Output.Len;
266
267 while (Rx->SYNC_LockStatus()) {
268 for (int i = 0; i < dlen; i++) {
269 c = Rx->Output.Data[i];
270 if (!progdefaults.mt63_8bit) {
271 put_rx_char(c);
272 continue;
273 }
274 if ((c < 8) && (escape == 0))
275 continue;
276 if (c == 127) {
277 escape = 1;
278 continue;
279 }
280 if (escape) {
281 c += 128;
282 escape = 0;
283 }
284 put_rx_char(c);
285 }
286 for (int j = 0; j < len; j++)
287 emptyBuff->Data[j] = 0.0;
288 emptyBuff->Len = len;
289 InpLevel->Process(emptyBuff);
290 Rx->Process(emptyBuff);
291 dlen = Rx->Output.Len;
292 }
293 flushbuffer = false;
294
295 return;
296 }
297
restart()298 void mt63::restart()
299 {
300 int err;
301
302 put_MODEstatus(mode);
303 set_scope_mode(Digiscope::BLANK);
304
305 { // critical section
306 guard_lock dsp_lock(&mt63_mutex);
307
308 err = Tx->Preset(get_txfreq_woffset(), (int)bandwidth, Interleave == 64 ? 1 : 0);
309 if (err)
310 fprintf(stderr, "mt63_txinit: init failed\n");
311 flush = Tx->DataInterleave;
312
313 err = Rx->Preset( frequency, (int)bandwidth,
314 Interleave == 64 ? 1 : 0,
315 long_integral ? 32 : 16);
316 } // end critical section
317 if (err)
318 fprintf(stderr, "mt63_rxinit: init failed\n");
319 InpLevel->Preset(64.0, 0.75);
320 stopflag = false;
321 }
322
init()323 void mt63::init()
324 {
325 modem::init();
326 restart();
327 flushbuffer = false;
328 maxval = 0.0;
329
330 if (progdefaults.mt63_at500) {
331 frequency = 500 + bandwidth / 2;
332 modem::set_freq(frequency);
333 }
334 else if (progdefaults.mt63_centered) {
335 frequency = 1500;
336 modem::set_freq(frequency);
337 }
338 else if (progStatus.carrier != 0) {
339 set_freq(progStatus.carrier);
340 #if !BENCHMARK_MODE
341 progStatus.carrier = 0;
342 #endif
343 } else
344 set_freq(wf->Carrier());
345
346 }
347
mt63(trx_mode mt63_mode)348 mt63::mt63 (trx_mode mt63_mode) : modem()
349 {
350 mode = mt63_mode;
351 switch (mode) {
352 case MODE_MT63_500S:
353 Interleave = 32;
354 bandwidth = 500;
355 break;
356 case MODE_MT63_500L:
357 Interleave = 64;
358 bandwidth = 500;
359 break;
360 case MODE_MT63_1000S:
361 Interleave = 32;
362 bandwidth = 1000;
363 break;
364 case MODE_MT63_1000L:
365 Interleave = 64;
366 bandwidth = 1000;
367 break;
368 case MODE_MT63_2000S:
369 Interleave = 32;
370 bandwidth = 2000;
371 break;
372 case MODE_MT63_2000L:
373 Interleave = 64;
374 bandwidth = 2000;
375 break;
376 }
377
378 long_integral = progdefaults.mt63_rx_integration;
379
380 Tx = new MT63tx;
381 Rx = new MT63rx;
382
383 InpLevel = new dspLevelMonitor;
384 InpBuff = new double_buff;
385 emptyBuff = new double_buff;
386
387 samplerate = 8000;
388 fragmentsize = 1024;
389
390 }
391
~mt63()392 mt63::~mt63()
393 {
394 guard_lock dsp_lock(&mt63_mutex);
395
396 if (Tx) delete Tx;
397 if (Rx) delete Rx;
398
399 if (InpLevel) delete InpLevel;
400 if (InpBuff) delete InpBuff;
401 }
402
403 // W1HKJ
404 // user can select manual or fixed positioning of the MT63 encoder/decoder
405 // progdefaults.mt63_at500 TRUE ==> fixed position
set_freq(double f)406 void mt63::set_freq(double f)
407 {
408 if (progdefaults.mt63_at500)
409 frequency = 500 + bandwidth / 2;
410 else if (progdefaults.mt63_centered)
411 frequency = 1500;
412 else
413 frequency = f;
414
415 modem::set_freq(frequency);
416 rx_init();
417 }
418