dl-fldigi/src/mt63/mt63.cxx

345 wiersze
7.6 KiB
C++

// ----------------------------------------------------------------------------
// mt63.cxx -- MT63 modem for fldigi
//
// Copyright (C) 1999-2004 Pawel Jalocha, SP9VRC
// Copyright (c) 2007-2011 Dave Freese, W1HKJ
//
// This file is part of fldigi.
//
// Fldigi 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 3 of the License, or
// (at your option) any later version.
//
// Fldigi 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <config.h>
#include "configuration.h"
#include "fl_digi.h"
#include "status.h"
#include "mt63.h"
using namespace std;
bool startflag = true;
void mt63::tx_init(SoundBase *sb)
{
scard = sb;
Tx->Preset(frequency, (int)bandwidth, Interleave == 64 ? 1 : 0);
flush = Tx->DataInterleave;
videoText();
startflag = true;
}
void mt63::rx_init()
{
Rx->Preset( frequency,
(int)bandwidth,
Interleave == 64 ? 1 : 0,
long_integral ? 32 : 16 );
InpLevel->Preset(64.0, 0.75);
escape = 0;
}
double peak = 0.0;
int mt63::tx_process()
{
int c;
double maxval = 0;
rx_flush();
if (startflag == true) {
startflag = false;
if (progdefaults.mt63_usetones) {
double maxval = 0.0;
for (int i = 0; i < (bandwidth * progdefaults.mt63_tone_duration / 96); i++) {
Tx->SendTune( progdefaults.mt63_twotones );
for (int i = 0; i < Tx->Comb.Output.Len; i++)
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
maxval = fabs(Tx->Comb.Output.Data[i]);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
Tx->Comb.Output.Data[i] /= maxval;
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
}
}
for (int i = 0; i < Tx->DataInterleave; i++) Tx->SendChar(0);
}
c = get_tx_char();
if (c == 0x03) {
stopflag = true;
flush = Tx->DataInterleave;
}
if (c == -1 || stopflag == true) c = 0;
if (stopflag) {
stopflag = false;
while (--flush) {
Tx->SendChar(0);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
maxval = fabs(Tx->Comb.Output.Data[i]);
for (int i = 0; i < Tx->Comb.Output.Len; i++) {
Tx->Comb.Output.Data[i] /= maxval;
}
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
}
Tx->SendJam();
for (int i = 0; i < Tx->Comb.Output.Len; i++)
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
maxval = fabs(Tx->Comb.Output.Data[i]);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
Tx->Comb.Output.Data[i] /= maxval;
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
cwid();
return -1; /* we're done */
}
if ((progdefaults.mt63_8bit && c > 255) || (!progdefaults.mt63_8bit && c > 127))
c = '.';
put_echo_char(c);
if (c > 127) {
c &= 127;
Tx->SendChar(127);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
maxval = fabs(Tx->Comb.Output.Data[i]);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
Tx->Comb.Output.Data[i] /= maxval;
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
}
Tx->SendChar(c);
for (int i = 0; i < Tx->Comb.Output.Len; i++)
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
maxval = fabs(Tx->Comb.Output.Data[i]);
for (int i = 0; i < Tx->Comb.Output.Len; i++) {
Tx->Comb.Output.Data[i] /= maxval;
}
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
return 0;
}
int mt63::rx_process(const double *buf, int len)
{
double snr;
unsigned int c;
int i;
static char msg1[20];
static char msg2[20];
if (Interleave != progdefaults.mt63_interleave) {
Interleave = progdefaults.mt63_interleave;
restart();
}
if (long_integral != progdefaults.mt63_rx_integration) {
long_integral = progdefaults.mt63_rx_integration;
restart();
}
if (InpBuff->EnsureSpace(len) == -1) {
fprintf(stderr, "mt63_rxprocess: buffer error\n");
return -1;
}
for (i = 0; i < len; i++)
InpBuff->Data[i] = buf[i];
InpBuff->Len = len;
InpLevel->Process(InpBuff);
Rx->Process(InpBuff);
snr = Rx->FEC_SNR();
if (progStatus.sqlonoff && snr < progStatus.sldrSquelchValue) {
put_Status1("");
put_Status2("");
display_metric(0);
return 0;
}
if (snr > 99.9)
snr = 99.9;
display_metric(snr);
double s2n = 10.0*log10( snr == 0 ? 0.001 : snr);
snprintf(msg1, sizeof(msg1), "s/n %2d dB", (int)(floor(s2n)));
put_Status1(msg1);
snprintf(msg2, sizeof(msg2), "f/o %+4.1f Hz", Rx->TotalFreqOffset());
put_Status2(msg2, 5, STATUS_CLEAR);
for (i = 0; i < Rx->Output.Len; i++) {
c = Rx->Output.Data[i];
if (!progdefaults.mt63_8bit) {
put_rx_char(c);
continue;
}
if ((c < 8) && (escape == 0))
continue;
if (c == 127) {
escape = 1;
continue;
}
if (escape) {
c += 128;
escape = 0;
}
put_rx_char(c);
}
flushbuffer = true;
return 0;
}
void mt63::rx_flush()
{
unsigned int c;
int len = 512;
int dlen = 0;
if (!flushbuffer) return;
if (emptyBuff->EnsureSpace(len) == -1) {
flushbuffer = false;
return;
}
for (int j = 0; j < len; j++)
emptyBuff->Data[j] = 0.0;
emptyBuff->Len = len;
InpLevel->Process(emptyBuff);
Rx->Process(emptyBuff);
dlen = Rx->Output.Len;
while (Rx->SYNC_LockStatus()) {
for (int i = 0; i < dlen; i++) {
c = Rx->Output.Data[i];
if (!progdefaults.mt63_8bit) {
put_rx_char(c);
continue;
}
if ((c < 8) && (escape == 0))
continue;
if (c == 127) {
escape = 1;
continue;
}
if (escape) {
c += 128;
escape = 0;
}
put_rx_char(c);
}
for (int j = 0; j < len; j++)
emptyBuff->Data[j] = 0.0;
emptyBuff->Len = len;
InpLevel->Process(emptyBuff);
Rx->Process(emptyBuff);
dlen = Rx->Output.Len;
}
flushbuffer = false;
return;
}
void mt63::restart()
{
int err;
put_MODEstatus(mode);
set_scope_mode(Digiscope::BLANK);
err = Tx->Preset(frequency, (int)bandwidth, Interleave == 64 ? 1 : 0);
if (err)
fprintf(stderr, "mt63_txinit: init failed\n");
flush = Tx->DataInterleave;
err = Rx->Preset( frequency, (int)bandwidth,
Interleave == 64 ? 1 : 0,
long_integral ? 32 : 16);
if (err)
fprintf(stderr, "mt63_rxinit: init failed\n");
InpLevel->Preset(64.0, 0.75);
stopflag = false;
}
void mt63::init()
{
modem::init();
restart();
flushbuffer = false;
}
mt63::mt63 (trx_mode mt63_mode) : modem()
{
mode = mt63_mode;
switch (mode) {
case MODE_MT63_500:
bandwidth = 500;
break;
case MODE_MT63_1000:
bandwidth = 1000;
break;
case MODE_MT63_2000:
bandwidth = 2000;
break;
}
Interleave = progdefaults.mt63_interleave;
long_integral = progdefaults.mt63_rx_integration;
Tx = new MT63tx;
Rx = new MT63rx;
InpLevel = new dspLevelMonitor;
InpBuff = new double_buff;
emptyBuff = new double_buff;
samplerate = 8000;
fragmentsize = 1024;
}
mt63::~mt63()
{
if (Tx) delete Tx;
if (Rx) delete Rx;
if (InpLevel) delete InpLevel;
if (InpBuff) delete InpBuff;
}
// W1HKJ
// user can select manual or fixed positioning of the MT63 encoder/decoder
// progdefaults.mt63_at500 TRUE ==> fixed position
void mt63::set_freq(double f)
{
if (progdefaults.mt63_at500)
frequency = 500 + bandwidth / 2;
else
frequency = f;
modem::set_freq(frequency);
rx_init();
}