dl-fldigi/src/mt63/mt63.cxx

357 wiersze
7.4 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"
//------------------------------------------------------------------------------
#include "threads.h"
static pthread_mutex_t mt63_mutex = PTHREAD_MUTEX_INITIALIZER;
//------------------------------------------------------------------------------
using namespace std;
bool startflag = true;
void mt63::tx_init(SoundBase *sb)
{
guard_lock dsp_lock(&mt63_mutex);
scard = sb;
Tx->Preset(frequency, (int)bandwidth, Interleave == 64 ? 1 : 0);
flush = Tx->DataInterleave;
videoText();
startflag = true;
}
void mt63::rx_init()
{
guard_lock dsp_lock(&mt63_mutex);
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()
{
rx_flush();
// do not put above rx_flush()
guard_lock dsp_lock(&mt63_mutex);
int c;
if (startflag == true) {
startflag = false;
if (progdefaults.mt63_usetones) {
for (int i = 0; i < (bandwidth * progdefaults.mt63_tone_duration / 96); i++) {
Tx->SendTune( progdefaults.mt63_twotones );
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 == GET_TX_CHAR_ETX) {
stopflag = true;
flush = Tx->DataInterleave;
}
if (c == GET_TX_CHAR_NODATA || stopflag == true) c = 0;
if (stopflag) {
stopflag = false;
while (--flush) {
Tx->SendChar(0);
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
}
Tx->SendJam();
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
cwid();
return -1; /* we're done */
}
if (c > 255 || (!progdefaults.mt63_8bit && c > 127))
c = '.';
int sendc = c;
if (sendc > 127) {
sendc &= 127;
Tx->SendChar(127);
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
}
Tx->SendChar(sendc);
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
put_echo_char(c);
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];
double f_offset;
// 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];
{ // critical section
guard_lock dsp_lock(&mt63_mutex);
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;
}
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);
}
f_offset = Rx->TotalFreqOffset();
} // end critical section
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", f_offset);
put_Status2(msg2, 5, STATUS_CLEAR);
flushbuffer = true;
return 0;
}
void mt63::rx_flush()
{
guard_lock dsp_lock(&mt63_mutex);
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);
{ // critical section
guard_lock dsp_lock(&mt63_mutex);
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);
} // end critical section
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_500S:
Interleave = 32;
bandwidth = 500;
break;
case MODE_MT63_500L:
Interleave = 64;
bandwidth = 500;
break;
case MODE_MT63_1000S:
Interleave = 32;
bandwidth = 1000;
break;
case MODE_MT63_1000L:
Interleave = 64;
bandwidth = 1000;
break;
case MODE_MT63_2000S:
Interleave = 32;
bandwidth = 2000;
break;
case MODE_MT63_2000L:
Interleave = 64;
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()
{
guard_lock dsp_lock(&mt63_mutex);
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();
}