From 34f7198b1effbd8840d4a9d1d6d16405961d3a7f Mon Sep 17 00:00:00 2001 From: Dave Hibberd Date: Tue, 10 Oct 2023 23:20:38 +0100 Subject: [PATCH] updates to make it install to the right place --- QtSoundModem.cpp.bak | 2866 ---------------------- UZ7HOStuff.h.bak | 1049 -------- debian/install | 2 +- debian/qtsoundmodem.desktop | 2 +- il2p.c.bak | 4502 ----------------------------------- 5 files changed, 2 insertions(+), 8419 deletions(-) delete mode 100644 QtSoundModem.cpp.bak delete mode 100644 UZ7HOStuff.h.bak delete mode 100644 il2p.c.bak diff --git a/QtSoundModem.cpp.bak b/QtSoundModem.cpp.bak deleted file mode 100644 index 3efef28..0000000 --- a/QtSoundModem.cpp.bak +++ /dev/null @@ -1,2866 +0,0 @@ -/* -Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO - -This file is part of QtSoundModem - -QtSoundModem 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. - -QtSoundModem 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 QtSoundModem. If not, see http://www.gnu.org/licenses - -*/ - -// UZ7HO Soundmodem Port by John Wiseman G8BPQ - -// UZ7HO Soundmodem Port - -// Not Working 4psk100 FEC - -// Thoughts on Waterfall Display. - -// Original used a 2048 sample FFT giving 5.859375 Hz bins. We plotted 1024 points, giving a 0 to 6000 specrum - -// If we want say 300 to 3300 we need about half the bin size so twice the fft size. But should we also fit required range to window size? - -// Unless we resize the most displayed bit of the screen in around 900 pixels. So each bin should be 3300 / 900 = 3.66667 Hz or a FFT size of around 3273 - -#include "QtSoundModem.h" -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "UZ7HOStuff.h" - - -QImage *Constellation; -QImage *Waterfall[4] = { 0,0,0,0 }; -QImage *Header[4]; -QLabel *DCDLabel[4]; -QLineEdit *chanOffsetLabel[4]; -QImage *DCDLed[4]; - -QImage *RXLevel; - -QLabel *WaterfallCopy[2]; -QLabel *HeaderCopy[2]; - -QTextEdit * monWindowCopy; - -extern workerThread *t; -extern QtSoundModem * w; - -QList Ports = QSerialPortInfo::availablePorts(); - -void saveSettings(); -void getSettings(); -extern "C" void CloseSound(); -extern "C" void GetSoundDevices(); -extern "C" char modes_name[modes_count][20]; -extern "C" int speed[5]; -extern "C" int KISSPort; -extern "C" short rx_freq[5]; - -extern "C" int CaptureCount; -extern "C" int PlaybackCount; - -extern "C" int CaptureIndex; // Card number -extern "C" int PlayBackIndex; - -extern "C" char CaptureNames[16][256]; -extern "C" char PlaybackNames[16][256]; - -extern "C" int SoundMode; -extern "C" int multiCore; - -extern "C" int refreshModems; - -extern "C" int pnt_change[5]; -extern "C" int needRSID[4]; - -extern "C" int needSetOffset[4]; - -extern "C" float MagOut[4096]; -extern "C" float MaxMagOut; -extern "C" int MaxMagIndex; - -extern "C" -{ - int InitSound(BOOL Report); - void soundMain(); - void MainLoop(); - void modulator(UCHAR snd_ch, int buf_size); - void SampleSink(int LR, short Sample); - void doCalib(int Port, int Act); - int Freq_Change(int Chan, int Freq); - void set_speed(int snd_ch, int Modem); - void init_speed(int snd_ch); - void wf_pointer(int snd_ch); - void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); - void dofft(short * in, float * outr, float * outi); - void init_raduga(); - void wf_Scale(int Chan); - void AGW_Report_Modem_Change(int port); - char * strlop(char * buf, char delim); - void sendRSID(int Chan, int dropTX); - void RSIDinitfft(); - void il2p_init(int il2p_debug); -} - -void make_graph_buf(float * buf, short tap, QPainter * bitmap); - -int ModemA = 2; -int ModemB = 2; -int ModemC = 2; -int ModemD = 2; -int FreqA = 1500; -int FreqB = 1500; -int FreqC = 1500; -int FreqD = 1500; -int DCD = 50; - -char CWIDCall[128] = ""; -int CWIDInterval = 0; -int CWIDLeft = 0; -int CWIDRight = 0; -int CWIDType = 1; // on/off - -extern "C" { int RSID_SABM[4]; } -extern "C" { int RSID_UI[4]; } -extern "C" { int RSID_SetModem[4]; } - -int Closing = FALSE; // Set to stop background thread - -QRgb white = qRgb(255, 255, 255); -QRgb black = qRgb(0, 0, 0); - -QRgb green = qRgb(0, 255, 0); -QRgb red = qRgb(255, 0, 0); -QRgb yellow = qRgb(255, 255, 0); -QRgb cyan = qRgb(0, 255, 255); - -// Indexed colour list from ARDOPC - -#define WHITE 0 -#define Tomato 1 -#define Gold 2 -#define Lime 3 -#define Yellow 4 -#define Orange 5 -#define Khaki 6 -#define Cyan 7 -#define DeepSkyBlue 8 -#define RoyalBlue 9 -#define Navy 10 -#define Black 11 -#define Goldenrod 12 -#define Fuchsia 13 - -QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0), qRgb(0, 255, 0), - qRgb(255, 255, 0), qRgb(255, 165, 0), qRgb(240, 240, 140), qRgb(0, 255, 255), - qRgb(0, 191, 255), qRgb(65, 105, 225), qRgb(0, 0, 128), qRgb(0, 0, 0), - qRgb(218, 165, 32), qRgb(255, 0, 255) }; - -unsigned char WaterfallLines[2][80][4096] = { 0 }; -int NextWaterfallLine[2] = { 0 }; - -unsigned int LastLevel = 255; -unsigned int LastBusy = 255; - -extern "C" int UDPClientPort; -extern "C" int UDPServerPort; -extern "C" int TXPort; -extern char UDPHost[64]; - -QTimer *cwidtimer; - -QSystemTrayIcon * trayIcon = nullptr; - -int MintoTray = 1; - -int RSID_WF = 0; // Set to use RSID FFT for Waterfall. - -extern "C" void WriteDebugLog(char * Mess) -{ - qDebug() << Mess; -} - -void QtSoundModem::doupdateDCD(int Chan, int State) -{ - DCDLabel[Chan]->setVisible(State); -} - -extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); -extern "C" char * ShortDateTime(); - -extern "C" void mon_rsid(int snd_ch, char * RSID) -{ - int Len; - char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot - - sprintf(Msg, "%d:%s [%s%c]", snd_ch + 1, RSID, ShortDateTime(), 'R'); - - Len = strlen(Msg); - - if (Msg[Len - 1] != '\r') - { - Msg[Len++] = '\r'; - Msg[Len] = 0; - } - - emit t->sendtoTrace(Msg, 0); -} - -extern "C" void put_frame(int snd_ch, string * frame, char * code, int tx, int excluded) -{ - UNUSED(excluded); - - int Len; - char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot - - if (strcmp(code, "NON-AX25") == 0) - sprintf(Msg, "%d: Length, ShortDateTime(), 'R'); - else - sprintf(Msg, "%d:%s", snd_ch + 1, frame_monitor(frame, code, tx)); - - Len = strlen(Msg); - - if (Msg[Len - 1] != '\r') - { - Msg[Len++] = '\r'; - Msg[Len] = 0; - } - - emit t->sendtoTrace(Msg, tx); -} - -extern "C" void updateDCD(int Chan, bool State) -{ - emit t->updateDCD(Chan, State); -} - -bool QtSoundModem::eventFilter(QObject* obj, QEvent *evt) -{ - UNUSED(obj); - - if (evt->type() == QEvent::Resize) - { - return QWidget::event(evt); - } - - if (evt->type() == QEvent::WindowStateChange) - { - if (windowState().testFlag(Qt::WindowMinimized) == true) - w_state = WIN_MINIMIZED; - else - w_state = WIN_MAXIMIZED; - } -// if (evt->type() == QGuiApplication::applicationStateChanged) - this is a sigma; -// { -// qDebug() << "App State changed =" << evt->type() << endl; -// } - - return QWidget::event(evt); -} - -void QtSoundModem::resizeEvent(QResizeEvent* event) -{ - QMainWindow::resizeEvent(event); - - QRect r = geometry(); - - int A, B, C, W; - int modemBoxHeight = 30; - - ui.modeB->setVisible(soundChannel[1]); - ui.centerB->setVisible(soundChannel[1]); - ui.labelB->setVisible(soundChannel[1]); - DCDLabel[1]->setVisible(soundChannel[1]); - ui.RXOffsetB->setVisible(soundChannel[1]); - - ui.modeC->setVisible(soundChannel[2]); - ui.centerC->setVisible(soundChannel[2]); - ui.labelC->setVisible(soundChannel[2]); - DCDLabel[2]->setVisible(soundChannel[2]); - ui.RXOffsetC->setVisible(soundChannel[2]); - - ui.modeD->setVisible(soundChannel[3]); - ui.centerD->setVisible(soundChannel[3]); - ui.labelD->setVisible(soundChannel[3]); - DCDLabel[3]->setVisible(soundChannel[3]); - ui.RXOffsetD->setVisible(soundChannel[3]); - - if (soundChannel[2] || soundChannel[3]) - modemBoxHeight = 60; - - - A = r.height() - 25; // No waterfalls - - if (UsingBothChannels && Secondwaterfall) - { - // Two waterfalls - - ui.WaterfallA->setVisible(1); - ui.HeaderA->setVisible(1); - ui.WaterfallB->setVisible(1); - ui.HeaderB->setVisible(1); - - A = r.height() - 258; // Top of Waterfall A - B = A + 115; // Top of Waterfall B - } - else - { - // One waterfall - - // Could be Left or Right - - if (Firstwaterfall) - { - if (soundChannel[0] == RIGHT) - { - ui.WaterfallA->setVisible(0); - ui.HeaderA->setVisible(0); - ui.WaterfallB->setVisible(1); - ui.HeaderB->setVisible(1); - } - else - { - ui.WaterfallA->setVisible(1); - ui.HeaderA->setVisible(1); - ui.WaterfallB->setVisible(0); - ui.HeaderB->setVisible(0); - } - - A = r.height() - 145; // Top of Waterfall A - } - else - A = r.height() - 25; // Top of Waterfall A - } - - C = A - 150; // Bottom of Monitor, Top of connection list - W = r.width(); - - // Calc Positions of Waterfalls - - ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26))); - sessionTable->setGeometry(QRect(0, C, W, 175)); - - if (UsingBothChannels) - { - ui.HeaderA->setGeometry(QRect(0, A, W, 35)); - ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); - ui.HeaderB->setGeometry(QRect(0, B, W, 35)); - ui.WaterfallB->setGeometry(QRect(0, B + 35, W, 80)); - } - else - { - if (soundChannel[0] == RIGHT) - { - ui.HeaderB->setGeometry(QRect(0, A, W, 35)); - ui.WaterfallB->setGeometry(QRect(0, A + 35, W, 80)); - } - else - { - ui.HeaderA->setGeometry(QRect(0, A, W, 35)); - ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); - } - } -} - -QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) -{ - QAction * Act = new QAction(Label, parent); - Menu->addAction(Act); - - Act->setCheckable(true); - if (State) - Act->setChecked(true); - - parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); - - return Act; -} - -void QtSoundModem::menuChecked() -{ - QAction * Act = static_cast(QObject::sender()); - - int state = Act->isChecked(); - - if (Act == actWaterfall1) - { - int oldstate = Firstwaterfall; - Firstwaterfall = state; - - if (state != oldstate) - initWaterfall(0, state); - - } - else if (Act == actWaterfall2) - { - int oldstate = Secondwaterfall; - Secondwaterfall = state; - - if (state != oldstate) - initWaterfall(1, state); - - } - saveSettings(); -} - -void QtSoundModem::initWaterfall(int chan, int state) -{ - if (state == 1) - { - if (chan == 0) - { - ui.WaterfallA = new QLabel(ui.centralWidget); - WaterfallCopy[0] = ui.WaterfallA; - } - else - { - ui.WaterfallB = new QLabel(ui.centralWidget); - WaterfallCopy[1] = ui.WaterfallB; - } - Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32); - Waterfall[chan]->fill(black); - - } - else - { - delete(Waterfall[chan]); - Waterfall[chan] = 0; - } - - QSize Size(800, 602); // Not actually used, but Event constructor needs it - QResizeEvent *event = new QResizeEvent(Size, Size); - QApplication::sendEvent(this, event); -} - -// Local copies - -QLabel *RXOffsetLabel; -QSlider *RXOffset; - -QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) -{ - ui.setupUi(this); - - QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); - - if (MintoTray) - { - char popUp[256]; - sprintf(popUp, "QtSoundModem %d %d", AGWPort, KISSPort); - trayIcon = new QSystemTrayIcon(QIcon(":/QtSoundModem/soundmodem.ico"), this); - trayIcon->setToolTip(popUp); - trayIcon->show(); - - connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason))); - } - - - restoreGeometry(mysettings.value("geometry").toByteArray()); - restoreState(mysettings.value("windowState").toByteArray()); - - sessionTable = new QTableWidget(this); - - sessionTable->verticalHeader()->setVisible(FALSE); - sessionTable->verticalHeader()->setDefaultSectionSize(20); - sessionTable->horizontalHeader()->setDefaultSectionSize(68); - sessionTable->setRowCount(1); - sessionTable->setColumnCount(12); - m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction"; - - sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }"); - - sessionTable->setHorizontalHeaderLabels(m_TableHeader); - sessionTable->setColumnWidth(0, 80); - sessionTable->setColumnWidth(1, 80); - sessionTable->setColumnWidth(4, 76); - sessionTable->setColumnWidth(5, 76); - sessionTable->setColumnWidth(6, 80); - sessionTable->setColumnWidth(11, 72); - - for (int i = 0; i < modes_count; i++) - { - ui.modeA->addItem(modes_name[i]); - ui.modeB->addItem(modes_name[i]); - ui.modeC->addItem(modes_name[i]); - ui.modeD->addItem(modes_name[i]); - } - - // Set up Menus - - setupMenu = ui.menuBar->addMenu(tr("Settings")); - - actDevices = new QAction("Setup Devices", this); - setupMenu->addAction(actDevices); - - connect(actDevices, SIGNAL(triggered()), this, SLOT(clickedSlot())); - actDevices->setObjectName("actDevices"); - actModems = new QAction("Setup Modems", this); - actModems->setObjectName("actModems"); - setupMenu->addAction(actModems); - - connect(actModems, SIGNAL(triggered()), this, SLOT(clickedSlot())); - - actMintoTray = setupMenu->addAction("Minimize to Tray", this, SLOT(MinimizetoTray())); - actMintoTray->setCheckable(1); - actMintoTray->setChecked(MintoTray); - - viewMenu = ui.menuBar->addMenu(tr("&View")); - - actWaterfall1 = setupMenuLine(viewMenu, (char *)"First waterfall", this, Firstwaterfall); - actWaterfall2 = setupMenuLine(viewMenu, (char *)"Second Waterfall", this, Secondwaterfall); - - actCalib = ui.menuBar->addAction("&Calibration"); - connect(actCalib, SIGNAL(triggered()), this, SLOT(doCalibrate())); - - actRestartWF = ui.menuBar->addAction("Restart Waterfall"); - connect(actRestartWF, SIGNAL(triggered()), this, SLOT(doRestartWF())); - - actAbout = ui.menuBar->addAction("&About"); - connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout())); - - // Constellation = new QImage(91, 91, QImage::Format_RGB32); - - Header[0] = new QImage(1024, 35, QImage::Format_RGB32); - Header[1] = new QImage(1024, 35, QImage::Format_RGB32); - RXLevel = new QImage(150, 10, QImage::Format_RGB32); - - DCDLabel[0] = new QLabel(this); - DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA")); - DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12)); - DCDLabel[0]->setVisible(TRUE); - - DCDLabel[1] = new QLabel(this); - DCDLabel[1]->setObjectName(QString::fromUtf8("DCDLedB")); - DCDLabel[1]->setGeometry(QRect(575, 31, 12, 12)); - DCDLabel[1]->setVisible(TRUE); - - DCDLabel[2] = new QLabel(this); - DCDLabel[2]->setObjectName(QString::fromUtf8("DCDLedC")); - DCDLabel[2]->setGeometry(QRect(280, 61, 12, 12)); - DCDLabel[2]->setVisible(FALSE); - - DCDLabel[3] = new QLabel(this); - DCDLabel[3]->setObjectName(QString::fromUtf8("DCDLedD")); - DCDLabel[3]->setGeometry(QRect(575, 61, 12, 12)); - DCDLabel[3]->setVisible(FALSE); - - DCDLed[0] = new QImage(12, 12, QImage::Format_RGB32); - DCDLed[1] = new QImage(12, 12, QImage::Format_RGB32); - DCDLed[2] = new QImage(12, 12, QImage::Format_RGB32); - DCDLed[3] = new QImage(12, 12, QImage::Format_RGB32); - - DCDLed[0]->fill(red); - DCDLed[1]->fill(red); - DCDLed[2]->fill(red); - DCDLed[3]->fill(red); - - DCDLabel[0]->setPixmap(QPixmap::fromImage(*DCDLed[0])); - DCDLabel[1]->setPixmap(QPixmap::fromImage(*DCDLed[1])); - DCDLabel[2]->setPixmap(QPixmap::fromImage(*DCDLed[2])); - DCDLabel[3]->setPixmap(QPixmap::fromImage(*DCDLed[3])); - - chanOffsetLabel[0] = ui.RXOffsetA; - chanOffsetLabel[1] = ui.RXOffsetB; - chanOffsetLabel[2] = ui.RXOffsetC; - chanOffsetLabel[3] = ui.RXOffsetD; - - - // Waterfall[0]->setColorCount(16); - // Waterfall[1]->setColorCount(16); - - - // for (i = 0; i < 16; i++) - // { - // Waterfall[0]->setColor(i, vbColours[i]); - // Waterfall[1]->setColor(i, vbColours[i]); - // } - - WaterfallCopy[0] = ui.WaterfallA; - WaterfallCopy[1] = ui.WaterfallB; - - initWaterfall(0, 1); - initWaterfall(1, 1); - - Header[0]->fill(black); - Header[1]->fill(black); - - HeaderCopy[0] = ui.HeaderA; - HeaderCopy[1] = ui.HeaderB; - monWindowCopy = ui.monWindow; - - ui.monWindow->document()->setMaximumBlockCount(10000); - -// connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged())); - - ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0])); - ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1])); - - wf_pointer(soundChannel[0]); - wf_pointer(soundChannel[1]); - wf_Scale(0); - wf_Scale(1); - - // RefreshLevel(0); - // RXLevel->setPixmap(QPixmap::fromImage(*RXLevel)); - - connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.modeD, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); - - ui.modeA->setCurrentIndex(speed[0]); - ui.modeB->setCurrentIndex(speed[1]); - ui.modeC->setCurrentIndex(speed[2]); - ui.modeD->setCurrentIndex(speed[3]); - - ModemA = ui.modeA->currentIndex(); - - ui.centerA->setValue(rx_freq[0]); - ui.centerB->setValue(rx_freq[1]); - ui.centerC->setValue(rx_freq[2]); - ui.centerD->setValue(rx_freq[3]); - - connect(ui.centerA, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.centerB, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.centerC, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); - connect(ui.centerD, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); - - ui.DCDSlider->setValue(dcd_threshold); - - - char valChar[32]; - sprintf(valChar, "RX Offset %d", rxOffset); - ui.RXOffsetLabel->setText(valChar); - ui.RXOffset->setValue(rxOffset); - - RXOffsetLabel = ui.RXOffsetLabel; - RXOffset = ui.RXOffset; - - connect(ui.DCDSlider, SIGNAL(sliderMoved(int)), this, SLOT(clickedSlotI(int))); - connect(ui.RXOffset, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); - - - QObject::connect(t, SIGNAL(sendtoTrace(char *, int)), this, SLOT(sendtoTrace(char *, int)), Qt::QueuedConnection); - QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection); - - connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed())); - connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed())); - connect(ui.RXOffsetC, SIGNAL(returnPressed()), this, SLOT(returnPressed())); - connect(ui.RXOffsetD, SIGNAL(returnPressed()), this, SLOT(returnPressed())); - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); - timer->start(100); - - - cwidtimer = new QTimer(this); - connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer())); - - if (CWIDInterval) - cwidtimer->start(CWIDInterval * 60000); - - if (RSID_SetModem[0]) - { - RSID_WF = 1; - RSIDinitfft(); - } - il2p_init(1); -} - -void QtSoundModem::MinimizetoTray() -{ - MintoTray = actMintoTray->isChecked(); - saveSettings(); - QMessageBox::about(this, tr("QtSoundModem"), - tr("Program must be restarted to change Minimize mode")); -} - - -void QtSoundModem::TrayActivated(QSystemTrayIcon::ActivationReason reason) -{ - if (reason == 3) - { - showNormal(); - w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); - } -} - -extern "C" void sendCWID(char * strID, BOOL blnPlay, int Chan); - -void QtSoundModem::CWIDTimer() -{ - sendCWID(CWIDCall, CWIDType, 0); - calib_mode[0] = 4; -} - -void extSetOffset(int chan) -{ - char valChar[32]; - sprintf(valChar, "%d", chanOffset[chan]); - chanOffsetLabel[chan]->setText(valChar); - - wf_pointer(soundChannel[chan]); - - pnt_change[0] = 1; - pnt_change[1] = 1; - pnt_change[2] = 1; - pnt_change[3] = 1; - - return; -} - -void QtSoundModem::MyTimerSlot() -{ - // 100 mS Timer Event - - for (int i = 0; i < 4; i++) - { - - if (needSetOffset[i]) - { - needSetOffset[i] = 0; - extSetOffset(i); // Update GUI - } - } - - if (refreshModems) - { - refreshModems = 0; - - ui.modeA->setCurrentIndex(speed[0]); - ui.modeB->setCurrentIndex(speed[1]); - ui.modeC->setCurrentIndex(speed[2]); - ui.modeD->setCurrentIndex(speed[3]); - ui.centerA->setValue(rx_freq[0]); - ui.centerB->setValue(rx_freq[1]); - ui.centerC->setValue(rx_freq[2]); - ui.centerD->setValue(rx_freq[3]); - } - - show_grid(); -} - -void QtSoundModem::returnPressed() -{ - char Name[32]; - int Chan; - QString val; - - strcpy(Name, sender()->objectName().toUtf8()); - - Chan = Name[8] - 'A'; - - val = chanOffsetLabel[Chan]->text(); - - chanOffset[Chan] = val.toInt(); - needSetOffset[Chan] = 1; // Update GUI - - -} - - -void QtSoundModem::clickedSlotI(int i) -{ - char Name[32]; - - strcpy(Name, sender()->objectName().toUtf8()); - - if (strcmp(Name, "modeA") == 0) - { - ModemA = ui.modeA->currentIndex(); - set_speed(0, ModemA); - saveSettings(); - AGW_Report_Modem_Change(0); - return; - } - - if (strcmp(Name, "modeB") == 0) - { - ModemB = ui.modeB->currentIndex(); - set_speed(1, ModemB); - saveSettings(); - AGW_Report_Modem_Change(1); - return; - } - - if (strcmp(Name, "modeC") == 0) - { - ModemC = ui.modeC->currentIndex(); - set_speed(2, ModemC); - saveSettings(); - AGW_Report_Modem_Change(2); - return; - } - - if (strcmp(Name, "modeD") == 0) - { - ModemD = ui.modeD->currentIndex(); - set_speed(3, ModemD); - saveSettings(); - AGW_Report_Modem_Change(3); - return; - } - - if (strcmp(Name, "centerA") == 0) - { - if (i > 300) - { - QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); - ui.centerA->setValue(Freq_Change(0, i)); - settings->setValue("Modem/RXFreq1", ui.centerA->value()); - AGW_Report_Modem_Change(0); - - } - return; - } - - if (strcmp(Name, "centerB") == 0) - { - if (i > 300) - { - QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); - ui.centerB->setValue(Freq_Change(1, i)); - settings->setValue("Modem/RXFreq2", ui.centerB->value()); - AGW_Report_Modem_Change(1); - } - return; - } - - if (strcmp(Name, "centerC") == 0) - { - if (i > 300) - { - QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); - ui.centerC->setValue(Freq_Change(2, i)); - settings->setValue("Modem/RXFreq3", ui.centerC->value()); - AGW_Report_Modem_Change(2); - } - return; - } - - if (strcmp(Name, "centerD") == 0) - { - if (i > 300) - { - QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); - ui.centerD->setValue(Freq_Change(3, i)); - settings->setValue("Modem/RXFreq4", ui.centerD->value()); - AGW_Report_Modem_Change(3); - } - return; - } - - if (strcmp(Name, "DCDSlider") == 0) - { - dcd_threshold = i; - saveSettings(); - return; - } - - if (strcmp(Name, "RXOffset") == 0) - { - char valChar[32]; - rxOffset = i; - sprintf(valChar, "RX Offset %d",rxOffset); - ui.RXOffsetLabel->setText(valChar); - - wf_pointer(soundChannel[0]); - wf_pointer(soundChannel[1]); - - pnt_change[0] = 1; - pnt_change[1] = 1; - pnt_change[2] = 1; - pnt_change[3] = 1; - - saveSettings(); - return; - } - - - QMessageBox msgBox; - msgBox.setWindowTitle("MessageBox Title"); - msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); - msgBox.exec(); -} - - -void QtSoundModem::clickedSlot() -{ - char Name[32]; - - strcpy(Name, sender()->objectName().toUtf8()); - - if (strcmp(Name, "actDevices") == 0) - { - doDevices(); - return; - } - - if (strcmp(Name, "actModems") == 0) - { - doModems(); - return; - } - - if (strcmp(Name, "showBPF_A") == 0) - { - doFilter(0, 0); - return; - } - - if (strcmp(Name, "showTXBPF_A") == 0) - { - doFilter(0, 1); - return; - } - - if (strcmp(Name, "showLPF_A") == 0) - { - doFilter(0, 2); - return; - } - - - if (strcmp(Name, "showBPF_B") == 0) - { - doFilter(1, 0); - return; - } - - if (strcmp(Name, "showTXBPF_B") == 0) - { - doFilter(1, 1); - return; - } - - if (strcmp(Name, "showLPF_B") == 0) - { - doFilter(1, 2); - return; - } - - if (strcmp(Name, "Low_A") == 0) - { - handleButton(0, 1); - return; - } - - if (strcmp(Name, "High_A") == 0) - { - handleButton(0, 2); - return; - } - - if (strcmp(Name, "Both_A") == 0) - { - handleButton(0, 3); - return; - } - - if (strcmp(Name, "Stop_A") == 0) - { - handleButton(0, 0); - return; - } - - - if (strcmp(Name, "Low_B") == 0) - { - handleButton(1, 1); - return; - } - - if (strcmp(Name, "High_B") == 0) - { - handleButton(1, 2); - return; - } - - if (strcmp(Name, "Both_B") == 0) - { - handleButton(1, 3); - return; - } - - if (strcmp(Name, "Stop_B") == 0) - { - handleButton(1, 0); - return; - } - - if (strcmp(Name, "Low_C") == 0) - { - handleButton(2, 1); - return; - } - - if (strcmp(Name, "High_C") == 0) - { - handleButton(2, 2); - return; - } - - if (strcmp(Name, "Both_C") == 0) - { - handleButton(2, 3); - return; - } - - if (strcmp(Name, "Stop_C") == 0) - { - handleButton(2, 0); - return; - } - - if (strcmp(Name, "Low_D") == 0) - { - handleButton(3, 1); - return; - } - - if (strcmp(Name, "High_D") == 0) - { - handleButton(3, 2); - return; - } - - if (strcmp(Name, "Both_D") == 0) - { - handleButton(3, 3); - return; - } - - if (strcmp(Name, "Stop_D") == 0) - { - handleButton(3, 0); - return; - } - - QMessageBox msgBox; - msgBox.setWindowTitle("MessageBox Title"); - msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); - msgBox.exec(); -} - -Ui_ModemDialog * Dlg; - -QDialog * modemUI; -QDialog * deviceUI; - -void QtSoundModem::doModems() -{ - Dlg = new(Ui_ModemDialog); - - QDialog UI; - char valChar[10]; - - Dlg->setupUi(&UI); - - modemUI = &UI; - deviceUI = 0; - - myResize *resize = new myResize(); - - UI.installEventFilter(resize); - - sprintf(valChar, "%d", bpf[0]); - Dlg->BPFWidthA->setText(valChar); - sprintf(valChar, "%d", bpf[1]); - Dlg->BPFWidthB->setText(valChar); - sprintf(valChar, "%d", bpf[2]); - Dlg->BPFWidthC->setText(valChar); - sprintf(valChar, "%d", bpf[3]); - Dlg->BPFWidthD->setText(valChar); - - sprintf(valChar, "%d", txbpf[0]); - Dlg->TXBPFWidthA->setText(valChar); - sprintf(valChar, "%d", txbpf[1]); - Dlg->TXBPFWidthB->setText(valChar); - sprintf(valChar, "%d", txbpf[2]); - Dlg->TXBPFWidthC->setText(valChar); - sprintf(valChar, "%d", txbpf[3]); - Dlg->TXBPFWidthD->setText(valChar); - - sprintf(valChar, "%d", lpf[0]); - Dlg->LPFWidthA->setText(valChar); - sprintf(valChar, "%d", lpf[1]); - Dlg->LPFWidthB->setText(valChar); - sprintf(valChar, "%d", lpf[2]); - Dlg->LPFWidthC->setText(valChar); - sprintf(valChar, "%d", lpf[4]); - Dlg->LPFWidthD->setText(valChar); - - sprintf(valChar, "%d", BPF_tap[0]); - Dlg->BPFTapsA->setText(valChar); - sprintf(valChar, "%d", BPF_tap[1]); - Dlg->BPFTapsB->setText(valChar); - sprintf(valChar, "%d", BPF_tap[2]); - Dlg->BPFTapsC->setText(valChar); - sprintf(valChar, "%d", BPF_tap[3]); - Dlg->BPFTapsD->setText(valChar); - - sprintf(valChar, "%d", LPF_tap[0]); - Dlg->LPFTapsA->setText(valChar); - sprintf(valChar, "%d", LPF_tap[1]); - Dlg->LPFTapsB->setText(valChar); - sprintf(valChar, "%d", LPF_tap[2]); - Dlg->LPFTapsC->setText(valChar); - sprintf(valChar, "%d", LPF_tap[3]); - Dlg->LPFTapsD->setText(valChar); - - Dlg->preEmphAllA->setChecked(emph_all[0]); - - if (emph_all[0]) - Dlg->preEmphA->setDisabled(TRUE); - else - Dlg->preEmphA->setCurrentIndex(emph_db[0]); - - Dlg->preEmphAllB->setChecked(emph_all[1]); - - if (emph_all[1]) - Dlg->preEmphB->setDisabled(TRUE); - else - Dlg->preEmphB->setCurrentIndex(emph_db[1]); - - Dlg->preEmphAllC->setChecked(emph_all[2]); - - if (emph_all[2]) - Dlg->preEmphC->setDisabled(TRUE); - else - Dlg->preEmphC->setCurrentIndex(emph_db[2]); - - Dlg->preEmphAllD->setChecked(emph_all[3]); - - if (emph_all[3]) - Dlg->preEmphD->setDisabled(TRUE); - else - Dlg->preEmphD->setCurrentIndex(emph_db[3]); - - - Dlg->nonAX25A->setChecked(NonAX25[0]); - Dlg->nonAX25B->setChecked(NonAX25[1]); - Dlg->nonAX25C->setChecked(NonAX25[2]); - Dlg->nonAX25D->setChecked(NonAX25[3]); - - Dlg->KISSOptA->setChecked(KISS_opt[0]); - Dlg->KISSOptB->setChecked(KISS_opt[1]); - Dlg->KISSOptC->setChecked(KISS_opt[2]); - Dlg->KISSOptD->setChecked(KISS_opt[3]); - - sprintf(valChar, "%d", txdelay[0]); - Dlg->TXDelayA->setText(valChar); - sprintf(valChar, "%d", txdelay[1]); - Dlg->TXDelayB->setText(valChar); - sprintf(valChar, "%d", txdelay[2]); - Dlg->TXDelayC->setText(valChar); - sprintf(valChar, "%d", txdelay[3]); - Dlg->TXDelayD->setText(valChar); - - sprintf(valChar, "%d", txtail[0]); - Dlg->TXTailA->setText(valChar); - sprintf(valChar, "%d", txtail[1]); - Dlg->TXTailB->setText(valChar); - sprintf(valChar, "%d", txtail[2]); - Dlg->TXTailC->setText(valChar); - sprintf(valChar, "%d", txtail[3]); - Dlg->TXTailD->setText(valChar); - - Dlg->FrackA->setText(QString::number(frack_time[0])); - Dlg->FrackB->setText(QString::number(frack_time[1])); - Dlg->FrackC->setText(QString::number(frack_time[2])); - Dlg->FrackD->setText(QString::number(frack_time[3])); - - Dlg->RetriesA->setText(QString::number(fracks[0])); - Dlg->RetriesB->setText(QString::number(fracks[1])); - Dlg->RetriesC->setText(QString::number(fracks[2])); - Dlg->RetriesD->setText(QString::number(fracks[3])); - - sprintf(valChar, "%d", RCVR[0]); - Dlg->AddRXA->setText(valChar); - sprintf(valChar, "%d", RCVR[1]); - Dlg->AddRXB->setText(valChar); - sprintf(valChar, "%d", RCVR[2]); - Dlg->AddRXC->setText(valChar); - sprintf(valChar, "%d", RCVR[3]); - Dlg->AddRXD->setText(valChar); - - sprintf(valChar, "%d", rcvr_offset[0]); - Dlg->RXShiftA->setText(valChar); - - sprintf(valChar, "%d", rcvr_offset[1]); - Dlg->RXShiftB->setText(valChar); - - sprintf(valChar, "%d", rcvr_offset[2]); - Dlg->RXShiftC->setText(valChar); - sprintf(valChar, "%d", rcvr_offset[3]); - Dlg->RXShiftD->setText(valChar); - - // speed[1] - // speed[2]; - - Dlg->recoverBitA->setCurrentIndex(recovery[0]); - Dlg->recoverBitB->setCurrentIndex(recovery[1]); - Dlg->recoverBitC->setCurrentIndex(recovery[2]); - Dlg->recoverBitD->setCurrentIndex(recovery[3]); - - Dlg->fx25ModeA->setCurrentIndex(fx25_mode[0]); - Dlg->fx25ModeB->setCurrentIndex(fx25_mode[1]); - Dlg->fx25ModeC->setCurrentIndex(fx25_mode[2]); - Dlg->fx25ModeD->setCurrentIndex(fx25_mode[3]); - - Dlg->IL2PModeA->setCurrentIndex(il2p_mode[0]); - Dlg->IL2PModeB->setCurrentIndex(il2p_mode[1]); - Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); - Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); - - Dlg->CWIDCall->setText(CWIDCall); - Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); - - if (CWIDType) - Dlg->radioButton_2->setChecked(1); - else - Dlg->CWIDType->setChecked(1); - - Dlg->RSIDSABM_A->setChecked(RSID_SABM[0]); - Dlg->RSIDSABM_B->setChecked(RSID_SABM[1]); - Dlg->RSIDSABM_C->setChecked(RSID_SABM[2]); - Dlg->RSIDSABM_D->setChecked(RSID_SABM[3]); - - Dlg->RSIDUI_A->setChecked(RSID_UI[0]); - Dlg->RSIDUI_B->setChecked(RSID_UI[1]); - Dlg->RSIDUI_C->setChecked(RSID_UI[2]); - Dlg->RSIDUI_D->setChecked(RSID_UI[3]); - - Dlg->DigiCallsA->setText(MyDigiCall[0]); - Dlg->DigiCallsB->setText(MyDigiCall[1]); - Dlg->DigiCallsC->setText(MyDigiCall[2]); - Dlg->DigiCallsD->setText(MyDigiCall[3]); - - Dlg->RSID_1_SETMODEM->setChecked(RSID_SetModem[0]); - Dlg->RSID_2_SETMODEM->setChecked(RSID_SetModem[1]); - Dlg->RSID_3_SETMODEM->setChecked(RSID_SetModem[2]); - Dlg->RSID_4_SETMODEM->setChecked(RSID_SetModem[3]); - - connect(Dlg->showBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showTXBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showLPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); - - connect(Dlg->showBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showTXBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showLPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); - - connect(Dlg->showBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showTXBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showLPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); - - connect(Dlg->showBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showTXBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Dlg->showLPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); - - connect(Dlg->okButton, SIGNAL(clicked()), this, SLOT(modemaccept())); - connect(Dlg->modemSave, SIGNAL(clicked()), this, SLOT(modemSave())); - connect(Dlg->cancelButton, SIGNAL(clicked()), this, SLOT(modemreject())); - - connect(Dlg->SendRSID_1, SIGNAL(clicked()), this, SLOT(doRSIDA())); - connect(Dlg->SendRSID_2, SIGNAL(clicked()), this, SLOT(doRSIDB())); - connect(Dlg->SendRSID_3, SIGNAL(clicked()), this, SLOT(doRSIDC())); - connect(Dlg->SendRSID_4, SIGNAL(clicked()), this, SLOT(doRSIDD())); - - connect(Dlg->preEmphAllA, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllAChanged(int))); - connect(Dlg->preEmphAllB, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllBChanged(int))); - connect(Dlg->preEmphAllC, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllCChanged(int))); - connect(Dlg->preEmphAllD, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllDChanged(int))); - - UI.exec(); -} - -void QtSoundModem::preEmphAllAChanged(int state) -{ - Dlg->preEmphA->setDisabled(state); -} - -void QtSoundModem::preEmphAllBChanged(int state) -{ - Dlg->preEmphB->setDisabled(state); -} - -void QtSoundModem::preEmphAllCChanged(int state) -{ - Dlg->preEmphC->setDisabled(state); -} - -void QtSoundModem::preEmphAllDChanged(int state) -{ - Dlg->preEmphD->setDisabled(state); -} - -extern "C" void get_exclude_list(char * line, TStringList * list); - -void QtSoundModem::modemaccept() -{ - modemSave(); - delete(Dlg); - saveSettings(); - - modemUI->accept(); - -} - -void QtSoundModem::modemSave() -{ - QVariant Q; - - emph_all[0] = Dlg->preEmphAllA->isChecked(); - emph_db[0] = Dlg->preEmphA->currentIndex(); - - emph_all[1] = Dlg->preEmphAllB->isChecked(); - emph_db[1] = Dlg->preEmphB->currentIndex(); - - emph_all[2] = Dlg->preEmphAllC->isChecked(); - emph_db[2] = Dlg->preEmphC->currentIndex(); - - emph_all[3] = Dlg->preEmphAllD->isChecked(); - emph_db[3] = Dlg->preEmphD->currentIndex(); - - NonAX25[0] = Dlg->nonAX25A->isChecked(); - NonAX25[1] = Dlg->nonAX25B->isChecked(); - NonAX25[2] = Dlg->nonAX25C->isChecked(); - NonAX25[3] = Dlg->nonAX25D->isChecked(); - - KISS_opt[0] = Dlg->KISSOptA->isChecked(); - KISS_opt[1] = Dlg->KISSOptB->isChecked(); - KISS_opt[2] = Dlg->KISSOptC->isChecked(); - KISS_opt[3] = Dlg->KISSOptD->isChecked(); - - if (emph_db[0] < 0 || emph_db[0] > nr_emph) - emph_db[0] = 0; - - if (emph_db[1] < 0 || emph_db[1] > nr_emph) - emph_db[1] = 0; - - if (emph_db[2] < 0 || emph_db[2] > nr_emph) - emph_db[2] = 0; - - if (emph_db[3] < 0 || emph_db[3] > nr_emph) - emph_db[3] = 0; - - Q = Dlg->TXDelayA->text(); - txdelay[0] = Q.toInt(); - - Q = Dlg->TXDelayB->text(); - txdelay[1] = Q.toInt(); - - Q = Dlg->TXDelayC->text(); - txdelay[2] = Q.toInt(); - - Q = Dlg->TXDelayD->text(); - txdelay[3] = Q.toInt(); - - Q = Dlg->TXTailA->text(); - txtail[0] = Q.toInt(); - - Q = Dlg->TXTailB->text(); - txtail[1] = Q.toInt(); - - Q = Dlg->TXTailC->text(); - txtail[2] = Q.toInt(); - - txtail[3] = Dlg->TXTailD->text().toInt(); - - frack_time[0] = Dlg->FrackA->text().toInt(); - frack_time[1] = Dlg->FrackB->text().toInt(); - frack_time[2] = Dlg->FrackC->text().toInt(); - frack_time[3] = Dlg->FrackD->text().toInt(); - - fracks[0] = Dlg->RetriesA->text().toInt(); - fracks[1] = Dlg->RetriesB->text().toInt(); - fracks[2] = Dlg->RetriesC->text().toInt(); - fracks[3] = Dlg->RetriesD->text().toInt(); - - Q = Dlg->AddRXA->text(); - RCVR[0] = Q.toInt(); - - Q = Dlg->AddRXB->text(); - RCVR[1] = Q.toInt(); - - Q = Dlg->AddRXC->text(); - RCVR[2] = Q.toInt(); - - Q = Dlg->AddRXD->text(); - RCVR[3] = Q.toInt(); - - Q = Dlg->RXShiftA->text(); - rcvr_offset[0] = Q.toInt(); - - Q = Dlg->RXShiftB->text(); - rcvr_offset[1] = Q.toInt(); - - Q = Dlg->RXShiftC->text(); - rcvr_offset[2] = Q.toInt(); - - Q = Dlg->RXShiftD->text(); - rcvr_offset[3] = Q.toInt(); - - fx25_mode[0] = Dlg->fx25ModeA->currentIndex(); - fx25_mode[1] = Dlg->fx25ModeB->currentIndex(); - fx25_mode[2] = Dlg->fx25ModeC->currentIndex(); - fx25_mode[3] = Dlg->fx25ModeD->currentIndex(); - - il2p_mode[0] = Dlg->IL2PModeA->currentIndex(); - il2p_mode[1] = Dlg->IL2PModeB->currentIndex(); - il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); - il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); - - recovery[0] = Dlg->recoverBitA->currentIndex(); - recovery[1] = Dlg->recoverBitB->currentIndex(); - recovery[2] = Dlg->recoverBitC->currentIndex(); - recovery[3] = Dlg->recoverBitD->currentIndex(); - - - strcpy(CWIDCall, Dlg->CWIDCall->text().toUtf8().toUpper()); - CWIDInterval = Dlg->CWIDInterval->text().toInt(); - CWIDType = Dlg->radioButton_2->isChecked(); - - if (CWIDInterval) - cwidtimer->start(CWIDInterval * 60000); - else - cwidtimer->stop(); - - - RSID_SABM[0] = Dlg->RSIDSABM_A->isChecked(); - RSID_SABM[1] = Dlg->RSIDSABM_B->isChecked(); - RSID_SABM[2] = Dlg->RSIDSABM_C->isChecked(); - RSID_SABM[3] = Dlg->RSIDSABM_D->isChecked(); - - RSID_UI[0] = Dlg->RSIDUI_A->isChecked(); - RSID_UI[1] = Dlg->RSIDUI_B->isChecked(); - RSID_UI[2] = Dlg->RSIDUI_C->isChecked(); - RSID_UI[3] = Dlg->RSIDUI_D->isChecked(); - - RSID_SetModem[0] = Dlg->RSID_1_SETMODEM->isChecked(); - RSID_SetModem[1] = Dlg->RSID_2_SETMODEM->isChecked(); - RSID_SetModem[2] = Dlg->RSID_3_SETMODEM->isChecked(); - RSID_SetModem[3] = Dlg->RSID_4_SETMODEM->isChecked(); - - Q = Dlg->DigiCallsA->text(); - strcpy(MyDigiCall[0], Q.toString().toUtf8().toUpper()); - - Q = Dlg->DigiCallsB->text(); - strcpy(MyDigiCall[1], Q.toString().toUtf8().toUpper()); - - Q = Dlg->DigiCallsC->text(); - strcpy(MyDigiCall[2], Q.toString().toUtf8().toUpper()); - - Q = Dlg->DigiCallsD->text(); - strcpy(MyDigiCall[3], Q.toString().toUtf8().toUpper()); - - int i; - - for (i = 0; i < 4; i++) - { - initTStringList(&list_digi_callsigns[i]); - - get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); - } - -} - -void QtSoundModem::modemreject() -{ - delete(Dlg); - modemUI->reject(); -} - -void QtSoundModem::doRSIDA() -{ - needRSID[0] = 1; -} - -void QtSoundModem::doRSIDB() -{ - needRSID[1] = 1; -} - -void QtSoundModem::doRSIDC() -{ - needRSID[2] = 1; -} - -void QtSoundModem::doRSIDD() -{ - needRSID[3] = 1; -} - - - - -void QtSoundModem::doFilter(int Chan, int Filter) -{ - Ui_Dialog Dev; - QImage * bitmap; - - QDialog UI; - - Dev.setupUi(&UI); - - bitmap = new QImage(642, 312, QImage::Format_RGB32); - - bitmap->fill(qRgb(255, 255, 255)); - - QPainter qPainter(bitmap); - qPainter.setBrush(Qt::NoBrush); - qPainter.setPen(Qt::black); - - if (Filter == 0) - make_graph_buf(DET[0][0].BPF_core[Chan], BPF_tap[Chan], &qPainter); - else if (Filter == 1) - make_graph_buf(tx_BPF_core[Chan], tx_BPF_tap[Chan], &qPainter); - else - make_graph_buf(LPF_core[Chan], LPF_tap[Chan], &qPainter); - - qPainter.end(); - Dev.label->setPixmap(QPixmap::fromImage(*bitmap)); - - UI.exec(); - -} - -Ui_devicesDialog * Dev; - -char NewPTTPort[80]; - -int newSoundMode = 0; -int oldSoundMode = 0; - -void QtSoundModem::SoundModeChanged(bool State) -{ - UNUSED(State); - - // Mustn't change SoundMode until dialog is accepted - - if (Dev->UDP->isChecked()) - newSoundMode = 3; - else if (Dev->PULSE->isChecked()) - newSoundMode = 2; - else - newSoundMode = Dev->OSS->isChecked(); - -} - -void QtSoundModem::DualPTTChanged(bool State) -{ - UNUSED(State); - - // Forse Evaluation of Cat Port setting - - PTTPortChanged(0); -} - -void QtSoundModem::CATChanged(bool State) -{ - UNUSED(State); - PTTPortChanged(0); -} - -void QtSoundModem::PTTPortChanged(int Selected) -{ - UNUSED(Selected); - - QVariant Q = Dev->PTTPort->currentText(); - strcpy(NewPTTPort, Q.toString().toUtf8()); - - Dev->RTSDTR->setVisible(false); - Dev->CAT->setVisible(false); - - Dev->PTTOnLab->setVisible(false); - Dev->PTTOn->setVisible(false); - Dev->PTTOff->setVisible(false); - Dev->PTTOffLab->setVisible(false); - Dev->CATLabel->setVisible(false); - Dev->CATSpeed->setVisible(false); - - Dev->GPIOLab->setVisible(false); - Dev->GPIOLeft->setVisible(false); - Dev->GPIORight->setVisible(false); - Dev->GPIOLab2->setVisible(false); - - Dev->CM108Label->setVisible(false); - Dev->VIDPID->setVisible(false); - - if (strcmp(NewPTTPort, "None") == 0) - { - } - else if (strcmp(NewPTTPort, "GPIO") == 0) - { - Dev->GPIOLab->setVisible(true); - Dev->GPIOLeft->setVisible(true); - if (Dev->DualPTT->isChecked()) - { - Dev->GPIORight->setVisible(true); - Dev->GPIOLab2->setVisible(true); - } - } - - else if (strcmp(NewPTTPort, "CM108") == 0) - { - Dev->CM108Label->setVisible(true); -//#ifdef __ARM_ARCHX - Dev->CM108Label->setText("CM108 Device"); -//#else -// Dev->CM108Label->setText("CM108 VID/PID"); -//#endif - Dev->VIDPID->setText(CM108Addr); - Dev->VIDPID->setVisible(true); - } - else if (strcmp(NewPTTPort, "HAMLIB") == 0) - { - Dev->CM108Label->setVisible(true); - Dev->CM108Label->setText("rigctrld Port"); - Dev->VIDPID->setText(QString::number(HamLibPort)); - Dev->VIDPID->setVisible(true); - Dev->PTTOnLab->setText("rigctrld Host"); - Dev->PTTOnLab->setVisible(true); - Dev->PTTOn->setText(HamLibHost); - Dev->PTTOn->setVisible(true); - } - else - { - Dev->RTSDTR->setVisible(true); - Dev->CAT->setVisible(true); - - if (Dev->CAT->isChecked()) - { - Dev->PTTOnLab->setVisible(true); - Dev->PTTOnLab->setText("PTT On String"); - Dev->PTTOn->setText(PTTOnString); - Dev->PTTOn->setVisible(true); - Dev->PTTOff->setVisible(true); - Dev->PTTOff->setText(PTTOffString); - Dev->PTTOffLab->setVisible(true); - Dev->CATLabel->setVisible(true); - Dev->CATSpeed->setVisible(true); - } - } -} - -bool myResize::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::Resize) - { - QResizeEvent *resizeEvent = static_cast(event); - QSize size = resizeEvent->size(); - int h = size.height(); - int w = size.width(); - - if (obj == deviceUI) - Dev->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); - else - Dlg->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); - - return true; - } - return QObject::eventFilter(obj, event); -} - -void QtSoundModem::doDevices() -{ - char valChar[10]; - - Dev = new(Ui_devicesDialog); - - QDialog UI; - - int i; - - Dev->setupUi(&UI); - - deviceUI = &UI; - modemUI = 0; - - myResize *resize = new myResize(); - - UI.installEventFilter(resize); - - newSoundMode = SoundMode; - oldSoundMode = SoundMode; - -#ifdef WIN32 - Dev->ALSA->setText("WaveOut"); - Dev->OSS->setVisible(0); - Dev->PULSE->setVisible(0); -#endif - - if (SoundMode == 0) - Dev->ALSA->setChecked(1); - else if (SoundMode == 1) - Dev->OSS->setChecked(1); - else if (SoundMode == 2) - Dev->PULSE->setChecked(1); - else if (SoundMode == 2) - Dev->UDP->setChecked(1); - - connect(Dev->ALSA, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); - connect(Dev->OSS, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); - connect(Dev->PULSE, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); - connect(Dev->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); - - for (i = 0; i < PlaybackCount; i++) - Dev->outputDevice->addItem(&PlaybackNames[i][0]); - - i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); - - - if (i == -1) - { - // Add device to list - - Dev->outputDevice->addItem(PlaybackDevice); - i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); - } - - Dev->outputDevice->setCurrentIndex(i); - - for (i = 0; i < CaptureCount; i++) - Dev->inputDevice->addItem(&CaptureNames[i][0]); - - i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); - - if (i == -1) - { - // Add device to list - - Dev->inputDevice->addItem(CaptureDevice); - i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); - } - Dev->inputDevice->setCurrentIndex(i); - - Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]); - Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]); - Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]); - Dev->Modem_4_Chan->setCurrentIndex(soundChannel[3]); - - // Disable "None" option in first modem - - QStandardItemModel *model = dynamic_cast(Dev->Modem_1_Chan->model()); - QStandardItem * item = model->item(0, 0); - item->setEnabled(false); - - Dev->singleChannelOutput->setChecked(SCO); - Dev->colourWaterfall->setChecked(raduga); - - sprintf(valChar, "%d", KISSPort); - Dev->KISSPort->setText(valChar); - Dev->KISSEnabled->setChecked(KISSServ); - - sprintf(valChar, "%d", AGWPort); - Dev->AGWPort->setText(valChar); - Dev->AGWEnabled->setChecked(AGWServ); - - Dev->PTTOn->setText(PTTOnString); - Dev->PTTOff->setText(PTTOffString); - - sprintf(valChar, "%d", PTTBAUD); - Dev->CATSpeed->setText(valChar); - - sprintf(valChar, "%d", UDPClientPort); - Dev->UDPPort->setText(valChar); - Dev->UDPTXHost->setText(UDPHost); - - if (UDPServerPort != TXPort) - sprintf(valChar, "%d/%d", UDPServerPort, TXPort); - else - sprintf(valChar, "%d", UDPServerPort); - - Dev->UDPTXPort->setText(valChar); - - Dev->UDPEnabled->setChecked(UDPServ); - - sprintf(valChar, "%d", pttGPIOPin); - Dev->GPIOLeft->setText(valChar); - sprintf(valChar, "%d", pttGPIOPinR); - Dev->GPIORight->setText(valChar); - - Dev->VIDPID->setText(CM108Addr); - - QStringList items; - - connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); - connect(Dev->DualPTT, SIGNAL(toggled(bool)), this, SLOT(DualPTTChanged(bool))); - connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); - - - - if (PTTMode == PTTCAT) - Dev->CAT->setChecked(true); - else - Dev->RTSDTR->setChecked(true); - - for (const QSerialPortInfo &info : Ports) - { - items.append(info.portName()); - } - - items.sort(); - - Dev->PTTPort->addItem("None"); - Dev->PTTPort->addItem("CM108"); - - //#ifdef __ARM_ARCH - - Dev->PTTPort->addItem("GPIO"); - - //#endif - - Dev->PTTPort->addItem("HAMLIB"); - - for (const QString &info : items) - { - Dev->PTTPort->addItem(info); - } - - Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); - - PTTPortChanged(0); // Force reevaluation - - Dev->txRotation->setChecked(TX_rotate); - Dev->DualPTT->setChecked(DualPTT); - - Dev->multiCore->setChecked(multiCore); - - QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); - QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); - - UI.exec(); - -} - -void QtSoundModem::deviceaccept() -{ - QVariant Q = Dev->inputDevice->currentText(); - int cardChanged = 0; - char portString[32]; - - if (Dev->UDP->isChecked()) - { - // cant have server and slave - - if (Dev->UDPEnabled->isChecked()) - { - QMessageBox::about(this, tr("QtSoundModem"), - tr("Can't have UDP sound source and UDP server at same time")); - return; - } - } - - if (oldSoundMode != newSoundMode) - { - QMessageBox msgBox; - - msgBox.setText("QtSoundModem must restart to change Sound Mode.\n" - "Program will close if you hit Ok\n" - "You will need to reselect audio devices after restarting"); - - msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - int i = msgBox.exec(); - - if (i == QMessageBox::Ok) - { - SoundMode = newSoundMode; - - saveSettings(); - - Closing = 1; - return; - } - - if (oldSoundMode == 0) - Dev->ALSA->setChecked(1); - else if (oldSoundMode == 1) - Dev->OSS->setChecked(1); - else if (oldSoundMode == 2) - Dev->PULSE->setChecked(1); - else if (oldSoundMode == 3) - Dev->UDP->setChecked(1); - - QMessageBox::about(this, tr("Info"), - tr("

Changes not saved

")); - - return; - - } - - if (strcmp(CaptureDevice, Q.toString().toUtf8()) != 0) - { - strcpy(CaptureDevice, Q.toString().toUtf8()); - cardChanged = 1; - } - - CaptureIndex = Dev->inputDevice->currentIndex(); - - Q = Dev->outputDevice->currentText(); - - if (strcmp(PlaybackDevice, Q.toString().toUtf8()) != 0) - { - strcpy(PlaybackDevice, Q.toString().toUtf8()); - cardChanged = 1; - } - - PlayBackIndex = Dev->outputDevice->currentIndex(); - - soundChannel[0] = Dev->Modem_1_Chan->currentIndex(); - soundChannel[1] = Dev->Modem_2_Chan->currentIndex(); - soundChannel[2] = Dev->Modem_3_Chan->currentIndex(); - soundChannel[3] = Dev->Modem_4_Chan->currentIndex(); - - UsingLeft = 0; - UsingRight = 0; - UsingBothChannels = 0; - - for (int i = 0; i < 4; i++) - { - if (soundChannel[i] == LEFT) - { - UsingLeft = 1; - modemtoSoundLR[i] = 0; - } - else if (soundChannel[i] == RIGHT) - { - UsingRight = 1; - modemtoSoundLR[i] = 1; - } - } - - if (UsingLeft && UsingRight) - UsingBothChannels = 1; - - - SCO = Dev->singleChannelOutput->isChecked(); - raduga = Dev->colourWaterfall->isChecked(); - AGWServ = Dev->AGWEnabled->isChecked(); - KISSServ = Dev->KISSEnabled->isChecked(); - - Q = Dev->KISSPort->text(); - KISSPort = Q.toInt(); - - Q = Dev->AGWPort->text(); - AGWPort = Q.toInt(); - - Q = Dev->PTTPort->currentText(); - strcpy(PTTPort, Q.toString().toUtf8()); - - DualPTT = Dev->DualPTT->isChecked(); - TX_rotate = Dev->txRotation->isChecked(); - multiCore = Dev->multiCore->isChecked(); - - if (Dev->CAT->isChecked()) - PTTMode = PTTCAT; - else - PTTMode = PTTRTS; - - Q = Dev->PTTOn->text(); - strcpy(PTTOnString, Q.toString().toUtf8()); - Q = Dev->PTTOff->text(); - strcpy(PTTOffString, Q.toString().toUtf8()); - - Q = Dev->CATSpeed->text(); - PTTBAUD = Q.toInt(); - - Q = Dev->UDPPort->text(); - UDPClientPort = Q.toInt(); - - - Q = Dev->UDPTXPort->text(); - strcpy(portString, Q.toString().toUtf8()); - UDPServerPort = atoi(portString); - - if (strchr(portString, '/')) - { - char * ptr = strlop(portString, '/'); - TXPort = atoi(ptr); - } - else - TXPort = UDPServerPort; - - Q = Dev->UDPTXHost->text(); - strcpy(UDPHost, Q.toString().toUtf8()); - - UDPServ = Dev->UDPEnabled->isChecked(); - - Q = Dev->GPIOLeft->text(); - pttGPIOPin = Q.toInt(); - - Q = Dev->GPIORight->text(); - pttGPIOPinR = Q.toInt(); - - Q = Dev->VIDPID->text(); - - if (strcmp(PTTPort, "CM108") == 0) - strcpy(CM108Addr, Q.toString().toUtf8()); - else if (strcmp(PTTPort, "HAMLIB") == 0) - { - HamLibPort = Q.toInt(); - Q = Dev->PTTOn->text(); - strcpy(HamLibHost, Q.toString().toUtf8()); - } - - ClosePTTPort(); - OpenPTTPort(); - - wf_pointer(soundChannel[0]); - wf_pointer(soundChannel[1]); - - delete(Dev); - saveSettings(); - deviceUI->accept(); - - if (cardChanged) - { - InitSound(1); - } - - // Reset title and tooltip in case ports changed - - char Title[128]; - sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort); - w->setWindowTitle(Title); - - sprintf(Title, "QtSoundModem %d %d", AGWPort, KISSPort); - if (trayIcon) - trayIcon->setToolTip(Title); - - QSize newSize(this->size()); - QSize oldSize(this->size()); - - QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); - - QCoreApplication::postEvent(this, myResizeEvent); -} - -void QtSoundModem::devicereject() -{ - delete(Dev); - deviceUI->reject(); -} - -void QtSoundModem::handleButton(int Port, int Type) -{ - // interlock calib with CWID - - if (calib_mode[0] == 4) // CWID - return; - - doCalib(Port, Type); -} - -void QtSoundModem::doRestartWF() -{ - if (Firstwaterfall) - { - initWaterfall(0, 0); - initWaterfall(0, 1); - } - - if (Secondwaterfall) - { - initWaterfall(1, 0); - initWaterfall(1, 1); - } -} - - -void QtSoundModem::doAbout() -{ - QMessageBox::about(this, tr("About"), - tr("G8BPQ's port of UZ7HO's Soundmodem\n\nCopyright (C) 2019-2020 Andrei Kopanchuk UZ7HO")); -} - -void QtSoundModem::doCalibrate() -{ - Ui_calDialog Calibrate; - { - QDialog UI; - Calibrate.setupUi(&UI); - - connect(Calibrate.Low_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Both_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Stop_A, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Low_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.High_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Both_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Stop_B, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Low_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.High_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Both_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Stop_C, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Low_D, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.High_D, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Both_D, SIGNAL(released()), this, SLOT(clickedSlot())); - connect(Calibrate.Stop_D, SIGNAL(released()), this, SLOT(clickedSlot())); - - /* - - connect(Calibrate.Low_A, &QPushButton::released, this, [=] { handleButton(0, 1); }); - connect(Calibrate.High_A, &QPushButton::released, this, [=] { handleButton(0, 2); }); - connect(Calibrate.Both_A, &QPushButton::released, this, [=] { handleButton(0, 3); }); - connect(Calibrate.Stop_A, &QPushButton::released, this, [=] { handleButton(0, 0); }); - connect(Calibrate.Low_B, &QPushButton::released, this, [=] { handleButton(1, 1); }); - connect(Calibrate.High_B, &QPushButton::released, this, [=] { handleButton(1, 2); }); - connect(Calibrate.Both_B, &QPushButton::released, this, [=] { handleButton(1, 3); }); - connect(Calibrate.Stop_B, &QPushButton::released, this, [=] { handleButton(1, 0); }); - -// connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(handleButton(1, 2))); -*/ - UI.exec(); - } -} - -void QtSoundModem::RefreshSpectrum(unsigned char * Data) -{ - int i; - - // Last 4 bytes are level busy and Tuning lines - - Waterfall[0]->fill(Black); - - if (Data[206] != LastLevel) - { - LastLevel = Data[206]; -// RefreshLevel(LastLevel); - } - - if (Data[207] != LastBusy) - { - LastBusy = Data[207]; -// Busy->setVisible(LastBusy); - } - - for (i = 0; i < 205; i++) - { - int val = Data[0]; - - if (val > 63) - val = 63; - - Waterfall[0]->setPixel(i, val, Yellow); - if (val < 62) - Waterfall[0]->setPixel(i, val + 1, Gold); - Data++; - } - - ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); - -} - -void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data) -{ - int j; - unsigned char * Line; - int len = Waterfall[0]->bytesPerLine(); - int TopLine = NextWaterfallLine[snd_ch]; - - // Write line to cyclic buffer then draw starting with the line just written - - // Length is 208 bytes, including Level and Busy flags - - memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Data, 206); - if (NextWaterfallLine[snd_ch] > 63) - NextWaterfallLine[snd_ch] = 0; - - for (j = 63; j > 0; j--) - { - Line = Waterfall[0]->scanLine(j); - memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len); - if (TopLine > 63) - TopLine = 0; - } - - ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); -} - - -void QtSoundModem::sendtoTrace(char * Msg, int tx) -{ - const QTextCursor old_cursor = monWindowCopy->textCursor(); - const int old_scrollbar_value = monWindowCopy->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == monWindowCopy->verticalScrollBar()->maximum(); - - // Move the cursor to the end of the document. - monWindowCopy->moveCursor(QTextCursor::End); - - // Insert the text at the position of the cursor (which is the end of the document). - - if (tx) - monWindowCopy->setTextColor(qRgb(192, 0, 0)); - else - monWindowCopy->setTextColor(qRgb(0, 0, 192)); - - monWindowCopy->textCursor().insertText(Msg); - - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - monWindowCopy->setTextCursor(old_cursor); - monWindowCopy->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - monWindowCopy->moveCursor(QTextCursor::End); - monWindowCopy->verticalScrollBar()->setValue(monWindowCopy->verticalScrollBar()->maximum()); - } - - free(Msg); -} - - -// I think this does the waterfall - -typedef struct TRGBQ_t -{ - Byte b, g, r, re; - -} TRGBWQ; - -typedef struct tagRECT -{ - int left; - int top; - int right; - int bottom; -} RECT; - -unsigned int RGBWF[256] ; - - -extern "C" void init_raduga() -{ - Byte offset[6] = {0, 51, 102, 153, 204}; - Byte i, n; - - for (n = 0; n < 52; n++) - { - i = n * 5; - - RGBWF[n + offset[0]] = qRgb(0, 0, i); - RGBWF[n + offset[1]] = qRgb(0, i, 255); - RGBWF[n + offset[2]] = qRgb(0, 255, 255 - i); - RGBWF[n + offset[3]] = qRgb(1, 255, 0); - RGBWF[n + offset[4]] = qRgb(255, 255 - 1, 0); - } -} - -extern "C" int nonGUIMode; - - -// This draws the Frequency Scale on Waterfall - -extern "C" void wf_Scale(int Chan) -{ - if (nonGUIMode) - return; - - float k; - int maxfreq, x, i; - char Textxx[20]; - QImage * bm = Header[Chan]; - - QPainter qPainter(bm); - qPainter.setBrush(Qt::black); - qPainter.setPen(Qt::white); - - maxfreq = roundf(RX_Samplerate*0.005); - k = 100 * fft_size / RX_Samplerate; - - if (Chan == 0) - sprintf(Textxx, "Left"); - else - sprintf(Textxx, "Right"); - - qPainter.drawText(2, 1, - 100, 20, 0, Textxx); - - for (i = 0; i < maxfreq; i++) - { - x = round(k*i); - if (x < 1025) - { - if ((i % 5) == 0) - qPainter.drawLine(x, 20, x, 13); - else - qPainter.drawLine(x, 20, x, 16); - - if ((i % 10) == 0) - { - sprintf(Textxx, "%d", i * 100); - - qPainter.drawText(x - 12, 1, - 100, 20, 0, Textxx); - } - } - } - HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm)); - -} - -// This draws the frequency Markers on the Waterfall - - -void do_pointer(int waterfall) -{ - if (nonGUIMode) - return; - - float x; - - int x1, x2, k, pos1, pos2, pos3; - QImage * bm = Header[waterfall]; - - QPainter qPainter(bm); - qPainter.setBrush(Qt::NoBrush); - qPainter.setPen(Qt::white); - - // bm->fill(black); - - qPainter.fillRect(0, 26, 1024, 9, Qt::black); - - k = 29; - x = fft_size / RX_Samplerate; - - // draw all enabled ports on the ports on this soundcard - - // First Modem is always on the first waterfall - // If second is enabled it is on the first unless different - // channel from first - - for (int i = 0; i < 4; i++) - { - if (UsingBothChannels == 0) - { - // Only One Waterfall. If first chan is - - if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) - return; - } - - if (soundChannel[i] == 0) - continue; - - - if (UsingBothChannels == 1) - if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) - continue; - - pos1 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i])*x) - 5; - pos2 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i])*x) - 5; - pos3 = roundf((rxOffset + chanOffset[i] + rx_freq[i]) * x); - x1 = pos1 + 5; - x2 = pos2 + 5; - - qPainter.setPen(Qt::white); - qPainter.drawLine(x1, k, x2, k); - qPainter.drawLine(x1, k - 3, x1, k + 3); - qPainter.drawLine(x2, k - 3, x2, k + 3); - qPainter.drawLine(pos3, k - 3, pos3, k + 3); - - if (rxOffset || chanOffset[i]) - { - // Draw TX posn if rxOffset used - - pos3 = roundf(rx_freq[i] * x); - qPainter.setPen(Qt::magenta); - qPainter.drawLine(pos3, k - 3, pos3, k + 3); - qPainter.drawLine(pos3, k - 3, pos3, k + 3); - qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3); - - } - } - HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm)); -} - -void wf_pointer(int snd_ch) -{ - UNUSED(snd_ch); - - do_pointer(0); - do_pointer(1); -// do_pointer(2); -// do_pointer(3); -} - - -void doWaterfallThread(void * param); - -/* -#ifdef WIN32 - -#define pthread_t uintptr_t - -extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); - -#else - -#include - -extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) -{ - pthread_t thread; - - if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) - perror("New Thread"); - else - pthread_detach(thread); - - return thread; -} - -#endif -*/ -extern "C" void doWaterfall(int snd_ch) -{ - if (nonGUIMode) - return; - - if (Closing) - return; - -// if (multiCore) // Run modems in separate threads -// _beginthread(doWaterfallThread, 0, xx); -// else - doWaterfallThread((void *)(size_t)snd_ch); - -} - - -extern "C" float aFFTAmpl[1024]; - -void doWaterfallThread(void * param) -{ - int snd_ch = (int)(size_t)param; - - QImage * bm = Waterfall[snd_ch]; - - word i, wid; - single mag; - UCHAR * p; - UCHAR Line[4096]; - - int lineLen; - word hfft_size; - Byte n; - float RealOut[4096] = { 0 }; - float ImagOut[4096]; - - QRegion exposed; - - hfft_size = fft_size / 2; - - // I think an FFT should produce n/2 bins, each of Samp/n Hz - // Looks like my code only works with n a power of 2 - - // So can use 1024 or 4096. 1024 gives 512 bins of 11.71875 and a 512 pixel - // display (is this enough?) - - // This does 2048 - - if (0) //RSID_WF - { - // Use the Magnitudes in float aFFTAmpl[RSID_FFT_SIZE]; - - for (i = 0; i < hfft_size; i++) - { - mag = aFFTAmpl[i]; - - mag *= 0.00000042f; - - if (mag < 0.00001f) - mag = 0.00001f; - - if (mag > 1.0f) - mag = 1.0f; - - mag = 22 * log2f(mag) + 255; - - if (mag < 0) - mag = 0; - - fft_disp[snd_ch][i] = round(mag); - } - } - else - { - dofft(&fft_buf[snd_ch][0], RealOut, ImagOut); - - // FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0); - - for (i = 0; i < hfft_size; i++) - { - //mag: = ComplexMag(fft_d[i])*0.00000042; - - // mag = sqrtf(powf(RealOut[i], 2) + powf(ImagOut[i], 2)) * 0.00000042f; - - mag = powf(RealOut[i], 2); - mag += powf(ImagOut[i], 2); - mag = sqrtf(mag); - mag *= 0.00000042f; - - - if (mag > MaxMagOut) - { - MaxMagOut = mag; - MaxMagIndex = i; - } - - if (mag < 0.00001f) - mag = 0.00001f; - - if (mag > 1.0f) - mag = 1.0f; - - mag = 22 * log2f(mag) + 255; - - if (mag < 0) - mag = 0; - - MagOut[i] = mag; - fft_disp[snd_ch][i] = round(mag); - } - } - - - - /* - for (i = 0; i < hfft_size; i++) - fft[i] = (powf(RealOut[i], 2) + powf(ImagOut[i], 2)); - - for (i = 0; i < hfft_size; i++) - { - if (fft[i] > max) - { - max = fft[i]; - imax = i; - } - } - - if (max > 0) - { - for (i = 0; i < hfft_size; i++) - fft[i] = fft[i] / max; - } - - - for (i = 0; i < hfft_size; i++) - { - mag = fft[i]; - - if (mag < 0.00001f) - mag = 0.00001f; - - if (mag > 1.0f) - mag = 1.0f; - - mag = 22 * log2f(mag) + 255; - - if (mag < 0) - mag = 0; - - fft_disp[snd_ch][i] = round(mag); - } - - */ - - // bm[snd_ch].Canvas.CopyRect(d, bm[snd_ch].canvas, s) - - //pm->scroll(0, 1, 0, 0, 1024, 80, &exposed); - - // Each bin is 12000 /2048 = 5.859375 - // I think we plot at 6 Hz per pixel. - - wid = bm->width(); - if (wid > hfft_size) - wid = hfft_size; - - wid = wid - 1; - - p = Line; - lineLen = bm->bytesPerLine(); - - if (wid > lineLen / 4) - wid = lineLen / 4; - - if (raduga == DISP_MONO) - { - for (i = 0; i < wid; i++) - { - n = fft_disp[snd_ch][i]; - *(p++) = n; // all colours the same - *(p++) = n; - *(p++) = n; - p++; - } - } - else - { - for (i = 0; i < wid; i++) - { - n = fft_disp[snd_ch][i]; - - memcpy(p, &RGBWF[n], 4); - p += 4; - } - } - - // Scroll - - int TopLine = NextWaterfallLine[snd_ch]; - - // Write line to cyclic buffer then draw starting with the line just written - - memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096); - if (NextWaterfallLine[snd_ch] > 79) - NextWaterfallLine[snd_ch] = 0; - - for (int j = 79; j > 0; j--) - { - p = bm->scanLine(j); - memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen); - TopLine++; - if (TopLine > 79) - TopLine = 0; - } - - WaterfallCopy[snd_ch]->setPixmap(QPixmap::fromImage(*bm)); - // WaterfallCopy[snd_ch - 1]->setPixmap(*pm); - // WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm)); - -} - - - -void QtSoundModem::changeEvent(QEvent* e) -{ - if (e->type() == QEvent::WindowStateChange) - { - QWindowStateChangeEvent* ev = static_cast(e); - - qDebug() << windowState(); - - if (!(ev->oldState() & Qt::WindowMinimized) && windowState() & Qt::WindowMinimized) - { - if (trayIcon) - setVisible(false); - } -// if (!(ev->oldState() != Qt::WindowNoState) && windowState() == Qt::WindowNoState) -// { -// QMessageBox::information(this, "", "Window has been restored"); -// } - - } - QWidget::changeEvent(e); -} - -#include - -void QtSoundModem::closeEvent(QCloseEvent *event) -{ - UNUSED(event); - - QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); - mysettings.setValue("geometry", QWidget::saveGeometry()); - mysettings.setValue("windowState", saveState()); - - Closing = TRUE; - qDebug() << "Closing"; - - QThread::msleep(100); -} - - -QtSoundModem::~QtSoundModem() -{ - qDebug() << "Saving Settings"; - - QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); - mysettings.setValue("geometry", saveGeometry()); - mysettings.setValue("windowState", saveState()); - - saveSettings(); - Closing = TRUE; - qDebug() << "Closing"; - - QThread::msleep(100); -} - -extern "C" void QSleep(int ms) -{ - QThread::msleep(ms); -} - -int upd_time = 30; - -void QtSoundModem::show_grid() -{ - // This refeshes the session list - - int snd_ch, i, num_rows, row_idx; - QTableWidgetItem *item; - const char * msg; - - int speed_tx, speed_rx; - - if (grid_time < 10) - { - grid_time++; - return; - } - - grid_time = 0; - - //label7.Caption = inttostr(stat_r_mem); mem_arq - - num_rows = 0; - row_idx = 0; - - for (snd_ch = 0; snd_ch < 4; snd_ch++) - { - for (i = 0; i < port_num; i++) - { - if (AX25Port[snd_ch][i].status != STAT_NO_LINK) - num_rows++; - } - } - - if (num_rows == 0) - { - sessionTable->clearContents(); - sessionTable->setRowCount(0); - sessionTable->setRowCount(1); - } - else - sessionTable->setRowCount(num_rows); - - - for (snd_ch = 0; snd_ch < 4; snd_ch++) - { - for (i = 0; i < port_num; i++) - { - if (AX25Port[snd_ch][i].status != STAT_NO_LINK) - { - switch (AX25Port[snd_ch][i].status) - { - case STAT_NO_LINK: - - msg = "No link"; - break; - - case STAT_LINK: - - msg = "Link"; - break; - - case STAT_CHK_LINK: - - msg = "Chk link"; - break; - - case STAT_WAIT_ANS: - - msg = "Wait ack"; - break; - - case STAT_TRY_LINK: - - msg = "Try link"; - break; - - case STAT_TRY_UNLINK: - - msg = "Try unlink"; - } - - - item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].mycall); - sessionTable->setItem(row_idx, 0, item); - - item = new QTableWidgetItem(AX25Port[snd_ch][i].kind); - sessionTable->setItem(row_idx, 11, item); - - item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].corrcall); - sessionTable->setItem(row_idx, 1, item); - - item = new QTableWidgetItem(msg); - sessionTable->setItem(row_idx, 2, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_pkt)); - sessionTable->setItem(row_idx, 3, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_byte)); - sessionTable->setItem(row_idx, 4, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_pkt)); - sessionTable->setItem(row_idx, 5, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_byte)); - sessionTable->setItem(row_idx, 6, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_fc)); - sessionTable->setItem(row_idx, 7, item); - - item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_fec_count)); - sessionTable->setItem(row_idx, 8, item); - - if (grid_timer != upd_time) - grid_timer++; - else - { - grid_timer = 0; - speed_tx = round(abs(AX25Port[snd_ch][i].info.stat_s_byte - AX25Port[snd_ch][i].info.stat_l_s_byte) / upd_time); - speed_rx = round(abs(AX25Port[snd_ch][i].info.stat_r_byte - AX25Port[snd_ch][i].info.stat_l_r_byte) / upd_time); - - item = new QTableWidgetItem(QString::number(speed_tx)); - sessionTable->setItem(row_idx, 9, item); - - item = new QTableWidgetItem(QString::number(speed_rx)); - sessionTable->setItem(row_idx, 10, item); - - AX25Port[snd_ch][i].info.stat_l_r_byte = AX25Port[snd_ch][i].info.stat_r_byte; - AX25Port[snd_ch][i].info.stat_l_s_byte = AX25Port[snd_ch][i].info.stat_s_byte; - } - - row_idx++; - } - } - } -} - -// "Copy on Select" Code - -void QtSoundModem::onTEselectionChanged() -{ - QTextEdit * x = static_cast(QObject::sender()); - x->copy(); -} - diff --git a/UZ7HOStuff.h.bak b/UZ7HOStuff.h.bak deleted file mode 100644 index b7e5ec8..0000000 --- a/UZ7HOStuff.h.bak +++ /dev/null @@ -1,1049 +0,0 @@ -// -// My port of UZ7HO's Soundmodem -// - -#define VersionString "0.0.0.65" -#define VersionBytes {0, 0, 0, 65} - -// Added FX25. 4x100 FEC and V27 not Working and disabled - -// 0.8 V27 now OK. - -// 0.9 Digipeating added - -// 0.10 Fix second channel tones and calibrate - -// 0.11 Fix allocation of sessions to correct modem -// Fix DCD -// Fix Monitoring of Multiline packets -// Fix possible saving of wrong center freq -// Limit TX sample Q in Linux -// - -// 0.12 Add AGWPE monitoring of received frames -// Fix DCD Threshold -// Fix KISS transparency issue - -// 0.13 Fix sending last few bits in FX.25 Mode - -// 0.14 Add "Copy on Select" to Trace Window - -// 0.15 Limit Trace window to 10000 lines - -// 0.16 Fix overwriting monitor window after scrollback - -// 0.17 Add GPIO and CAT PTT - -// 0.18 Add CM108/119 PTT - -// 0.19 Fix scheduling KISS frames - -// 0.20 Debug code added to RR processing - -// 0.21 Fix AGW monitor of multiple line packets -// Close ax.25 sessions if AGW Host session closes - -// 0.22 Add FEC Count to Session Stats - -// 0.23 Retry DISC until UA received or retry count exceeded - -// 0.24 More fixes to DISC handling - -// 0.26 Add OSS PulseAudio and HAMLIB support - -// 0.27 Dynamically load PulseAudio modules - -// 0.28 Add ARDOPPacket Mode - -// 0.29 Fix saving settings and geometry on close -// 0.30 Retructure code to build with Qt 5.3 -// Fix crash in nogui mode if pulse requested but not available -// Try to fix memory leaks - -// 0.31 Add option to run modems in seprate threads - -// 0.32 Fix timing problem with AGW connect at startup -// Add Memory ARQ -// Add Single bit "Correction" -// Fix error in 31 when using multiple decoders - -// 0.33 Fix Single bit correction -// More memory leak fixes - -// 0.34 Add API to set Modem and Center Frequency -// Fix crash in delete_incoming_mycalls - -// 0.35 Return Version in AGW Extended g response - -// 0.36 Fix timing problem on startup - -// 0.37 Add scrollbars to Device and Modem dialogs - -// 0.38 Change default CM108 name to /dev/hidraw0 on Linux - -// 0.39 Dont try to display Message Boxes in nogui mode. -// Close Device and Modem dialogs on Accept or Reject -// Fix using HAMLIB in nogui mode - -// 0.40 Fix bug in frame optimize when using 6 char calls - -// 0.41 Fix "glitch" on waterfall markers when changing modem freqs - -// 0.42 Add "Minimize to Tray" option - -// 0.43 Add Andy's on_SABM fix. -// Fix Crash if KISS Data sent to AGW port - -// 0.44 Add UDP bridge. - -// 0.45 Add two more modems. -// 0.46 Fix two more modems. - -// 0.47 Fix suprious DM when host connection lost -// Add CWID - -// 0.48 Send FRMR for unrecognised frame types - -// 0.49 Add Andy's FEC Tag correlation coode - -// 0.50 Fix Waterfall display when only using right channel -// Allow 1200 baud fsk at other center freqs -// Add Port numbers to Window title and Try Icon tooltip -// Fix calculation of filters for multiple decoders -// Add RX Offset setting (for satellite operation - -// 0.51 Fix Multithreading with more that 2 modems - -// 0.52 Add Stdin as source on Linux - -// 0.53 Use Byte instead of byte as byte is defined in newer versions of gcc - -// 0.54 Fix for ALSA problem on new pi OS - -// 0.55 Fix for compiler error with newer compiler - -// 0.56 Fix errors in Config.cpp June 22 - -// 0.57 Add Restart Waterfall action August 22 - -// 0.58 Add RSID Sept 2022 - -// 0.59 Add config of Digi Calls Dec 2022 - -// 0.60 Allow ARDOP Packet on modems 2 to 4 March 2023 - -// 0.61 Add il2p support April 2023 - -// 0.62 April 2023 -// Add option to specify sound devices that aren't in list -// Add Save button to Modem dialog to save current tab without closing dialog -// Don't add plug: to Linux device addresses unless addr contains : (allows use of eg ARDOP) - -// 0.64 Fix sending ax.25 (broken in .61) - -// 0.65 Allow Set Modem command to use modem index as well as modem name - - - -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UNUSED(x) (void)(x) - -#ifdef M_PI -#undef M_PI -#endif - -#define M_PI 3.1415926f - -#define pi M_PI - -#ifndef WIN32 -#define _strdup strdup -#endif - - //#define NULL ((void *)0) - - //Delphi Types remember case insensitive - -#define single float -#define boolean int -#define Byte unsigned char // 0 to 255 -#define Word unsigned short // 0 to 65,535 -#define SmallInt short // -32,768 to 32,767 -#define LongWord unsigned int // 0 to 4,294,967,295 - // Int6 : Cardinal; // 0 to 4,294,967,295 -#define LongInt int // -2,147,483,648 to 2,147,483,647 -#define Integer int // -2,147,483,648 to 2,147,483,647 -//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 - -//#define Byte unsigned char // 0 to 255 -#define word unsigned short // 0 to 65,535 -#define smallint short // -32,768 to 32,767 -#define longword unsigned int // 0 to 4,294,967,295 - // Int6 : Cardinal; // 0 to 4,294,967,295 -#define longint int // -2,147,483,648 to 2,147,483,647 -#define integer int // -2,147,483,648 to 2,147,483,647 - -typedef unsigned long ULONG; - -#define UCHAR unsigned char -#define UINT unsigned int -#define BOOL int -#define TRUE 1 -#define FALSE 0 - -// Soundcard Channels - -#define NONE 0 -#define LEFT 1 -#define RIGHT 2 - -#define nr_emph 2 - -#define decodedNormal 4 //'-' -#define decodedFEC 3 //'F' -#define decodedMEM 2 //'#' -#define decodedSingle 1 //'$' - - -// Seems to use Delphi TStringList for a lot of queues. This seems to be a list of pointers and a count -// Each pointer is to a Data/Length pair -//Maybe something like - -typedef struct string_T -{ - unsigned char * Data; - int Length; - int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars - -}string; - -typedef struct TStringList_T -{ - int Count; - string ** Items; - -} TStringList; - -// QPSK struct - -typedef struct TQPSK_t -{ - UCHAR tx[4]; - int count[4]; - UCHAR rx[4]; - UCHAR mode; -} TPQSK; - - -typedef struct TKISSMode_t -{ - string * data_in; - void * Socket; // Used as a key - - // Not sure what rest are used for. Seems to be one per channel - - TStringList buffer[4]; // Outgoing Frames - -} TKISSMode; - -typedef struct TMChannel_t -{ - - single prev_LPF1I_buf[4096]; - single prev_LPF1Q_buf[4096]; - single prev_dLPFI_buf[4096]; - single prev_dLPFQ_buf[4096]; - single prev_AFCI_buf[4096]; - single prev_AFCQ_buf[4096]; - single AngleCorr; - single MUX_osc; - single AFC_IZ1; - single AFC_IZ2; - single AFC_QZ1; - single AFC_QZ2; - single AFC_bit_buf1I[1024]; - single AFC_bit_buf1Q[1024]; - single AFC_bit_buf2[1024]; - single AFC_IIZ1; - single AFC_QQZ1; - -} TMChannel; - -typedef struct TFX25_t -{ - string data; - Byte status; - Byte bit_cnt; - Byte byte_rx; - unsigned long long tag; - Byte size; - Byte rs_size; - Byte size_cnt; -} TFX25; - - - -typedef struct TDetector_t -{ - struct TFX25_t fx25[4]; - TStringList mem_ARQ_F_buf[5]; - TStringList mem_ARQ_buf[5]; - float pll_loop[5]; - float last_sample[5]; - UCHAR ones[5]; - UCHAR zeros[5]; - float bit_buf[5][1024]; - float bit_buf1[5][1024]; - UCHAR sample_cnt[5]; - UCHAR last_bit[5]; - float PSK_IZ1[5]; - float PSK_QZ1[5]; - float PkAmpI[5]; - float PkAmpQ[5]; - float PkAmp[5]; - float PkAmpMax[5]; - int newpkpos[5]; - float AverageAmp[5]; - float AngleCorr[5]; - float MinAmp[5]; - float MaxAmp[5]; - float MUX3_osc[5]; - float MUX3_1_osc[5]; - float MUX3_2_osc[5]; - float Preemphasis6[5]; - float Preemphasis12[5]; - float PSK_AGC[5]; - float AGC[5]; - float AGC1[5]; - float AGC2[5]; - float AGC3[5]; - float AGC_max[5]; - float AGC_min[5]; - float AFC_IZ1[5]; - float AFC_IZ2[5]; - float AFC_QZ1[5]; - float AFC_QZ2[5]; - - UCHAR last_rx_bit[5]; - UCHAR bit_stream[5]; - UCHAR byte_rx[5]; - UCHAR bit_stuff_cnt[5]; - UCHAR bit_cnt[5]; - float bit_osc[5]; - UCHAR frame_status[5]; - string rx_data[5]; - string FEC_rx_data[5]; - // - UCHAR FEC_pol[5]; - unsigned short FEC_err[5]; - unsigned long long FEC_header1[5][2]; - unsigned short FEC_blk_int[5]; - unsigned short FEC_len_int[5]; - unsigned short FEC_len[5]; - - unsigned short FEC_len_cnt[5]; - - UCHAR rx_intv_tbl[5][4]; - UCHAR rx_intv_sym[5]; - UCHAR rx_viterbi[5]; - UCHAR viterbi_cnt[5]; - // SurvivorStates [1..4,0..511] of TSurvivor; - // - TMChannel MChannel[5][4]; - - float AFC_dF_avg[5]; - float AFC_dF[5]; - float AFC_bit_osc[5]; - float AFC_bit_buf[5][1024]; - unsigned short AFC_cnt[5]; - - string raw_bits1[5]; - string raw_bits[5]; - UCHAR last_nrzi_bit[5]; - - float BPF_core[5][2048]; - float LPF_core[5][2048]; - - float src_INTR_buf[5][8192]; - float src_INTRI_buf[5][8192]; - float src_INTRQ_buf[5][8192]; - float src_LPF1I_buf[5][8192]; - float src_LPF1Q_buf[5][8192]; - - float src_BPF_buf[5][2048]; - float src_Loop_buf[5][8192]; - float prev_BPF_buf[5][4096]; - - float prev_LPF1I_buf[5][4096]; - float prev_LPF1Q_buf[5][4096]; - float prev_INTR_buf[5][16384]; - float prev_INTRI_buf[5][16384]; - float prev_INTRQ_buf[5][16384]; - - Byte emph_decoded; - Byte rx_decoded; - Byte errors; - - -} TDetector; - - - -typedef struct AGWUser_t -{ - void *socket; - string * data_in; - TStringList AGW_frame_buf; - boolean Monitor; - boolean Monitor_raw; - boolean reportFreqAndModem; // Can report modem and frequency to host - -} AGWUser; - -typedef struct TAX25Info_t -{ - longint stat_s_pkt; - longint stat_s_byte; - longint stat_r_pkt; - longint stat_r_byte; - longint stat_r_fc; - longint stat_fec_count; - time_t stat_begin_ses; - time_t stat_end_ses; - longint stat_l_r_byte; - longint stat_l_s_byte; - -} TAX25Info; - -typedef struct TAX25Port_t -{ - Byte hi_vs; - Byte vs; - Byte vr; - Byte PID; - TStringList in_data_buf; - TStringList frm_collector; - string frm_win[8]; - string out_data_buf; - word t1; - word t2; - word t3; - Byte i_lo; - Byte i_hi; - word n1; - word n2; - word IPOLL_cnt; - TStringList frame_buf; //áóôåð êàäðîâ íà ïåðåäà÷ó - TStringList I_frame_buf; - Byte status; - word clk_frack; - char corrcall[10]; - char mycall[10]; - UCHAR digi[56]; - UCHAR Path[80]; // Path in ax25 format - added to save building it each time - UCHAR ReversePath[80]; - int snd_ch; // Simplifies parameter passing - int port; - int pathLen; - void * socket; - char kind[16]; - TAX25Info info; -} TAX25Port; - - -#define LOGEMERGENCY 0 -#define LOGALERT 1 -#define LOGCRIT 2 -#define LOGERROR 3 -#define LOGWARNING 4 -#define LOGNOTICE 5 -#define LOGINFO 6 -#define LOGDEBUG 7 - -#define PTTRTS 1 -#define PTTDTR 2 -#define PTTCAT 4 -#define PTTCM108 8 -#define PTTHAMLIB 16 - -// Status flags - -#define STAT_NO_LINK 0 -#define STAT_LINK 1 -#define STAT_CHK_LINK 2 -#define STAT_WAIT_ANS 3 -#define STAT_TRY_LINK 4 -#define STAT_TRY_UNLINK 5 - - - // Ñmd,Resp,Poll,Final,Digipeater flags -#define SET_P 1 -#define SET_F 0 -#define SET_C 1 -#define SET_R 0 -#define SET_NO_RPT 0 -#define SET_RPT 1 - // Frame ID flags -#define I_FRM 0 -#define S_FRM 1 -#define U_FRM 2 -#define I_I 0 -#define S_RR 1 -#define S_RNR 5 -#define S_REJ 9 -#define S_SREJ 0x0D -#define U_SABM 47 -#define U_DISC 67 -#define U_DM 15 -#define U_UA 99 -#define U_FRMR 135 -#define U_UI 3 - // PID flags -#define PID_X25 0x01 // 00000001-CCIT X25 PLP -#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment -#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol -#define PID_LQ 0xC4 // 11001000-Link Quality Protocol -#define PID_APPLETALK 0xCA // 11001010-Appletalk -#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP -#define PID_IP 0xCC // 11001100-ARPA Internet Protocol -#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol -#define PID_NET_ROM 0xCF // 11001111-NET/ROM - - -// Sound interface buffer size - -#define SendSize 1024 // 100 mS for now -#define ReceiveSize 512 // try 100 mS for now -#define NumberofinBuffers 4 - -#define Now getTicks() - -// #defines from all modules (?? is this a good idaa ?? - -#define WIN_MAXIMIZED 0 -#define WIN_MINIMIZED 1 -#define MODEM_CAPTION 'SoundModem by UZ7HO' -#define MODEM_VERSION '1.06' -#define SND_IDLE 0 -#define SND_RX 1 -#define SND_TX 2 -#define BUF_EMPTY 0 -#define BUF_FULL 1 -#define DISP_MONO FALSE -#define DISP_RGB TRUE -#define MOD_IDLE 0 -#define MOD_RX 1 -#define MOD_TX 2 -#define MOD_WAIT 3 -#define TIMER_FREE 0 -#define TIMER_BUSY 1 -#define TIMER_OFF 2 -#define TIMER_EVENT_ON 3 -#define TIMER_EVENT_OFF 4 -#define DEBUG_TIMER 1 -#define DEBUG_WATERFALL 2 -#define DEBUG_DECODE 4 -#define DEBUG_SOUND 8 -#define IS_LAST TRUE -#define IS_NOT_LAST FALSE -#define modes_count 16 -#define SPEED_300 0 -#define SPEED_1200 1 -#define SPEED_600 2 -#define SPEED_2400 3 -#define SPEED_P1200 4 -#define SPEED_P600 5 -#define SPEED_P300 6 -#define SPEED_P2400 7 -#define SPEED_Q4800 8 -#define SPEED_Q3600 9 -#define SPEED_Q2400 10 -#define SPEED_MP400 11 -#define SPEED_DW2400 12 -#define SPEED_8P4800 13 -#define SPEED_AE2400 14 -#define SPEED_ARDOP 15 - -#define MODE_FSK 0 -#define MODE_BPSK 1 -#define MODE_QPSK 2 -#define MODE_MPSK 3 -#define MODE_8PSK 4 -#define MODE_PI4QPSK 5 -#define MODE_ARDOP 6 - -#define QPSK_SM 0 -#define QPSK_V26 1 - - -#define MODEM_8P4800_BPF 3200 -#define MODEM_8P4800_TXBPF 3400 -#define MODEM_8P4800_LPF 1000 -#define MODEM_8P4800_BPF_TAP 64 -#define MODEM_8P4800_LPF_TAP 8 - // -#define MODEM_MP400_BPF 775 -#define MODEM_MP400_TXBPF 850 -#define MODEM_MP400_LPF 70 -#define MODEM_MP400_BPF_TAP 256 -#define MODEM_MP400_LPF_TAP 128 - // -#define MODEM_DW2400_BPF 2400 -#define MODEM_DW2400_TXBPF 2500 -#define MODEM_DW2400_LPF 900 -#define MODEM_DW2400_BPF_TAP 256 //256 -#define MODEM_DW2400_LPF_TAP 32 //128 - // -#define MODEM_Q2400_BPF 2400 -#define MODEM_Q2400_TXBPF 2500 -#define MODEM_Q2400_LPF 900 -#define MODEM_Q2400_BPF_TAP 256 //256 -#define MODEM_Q2400_LPF_TAP 128 //128 - // -#define MODEM_Q3600_BPF 3600 -#define MODEM_Q3600_TXBPF 3750 -#define MODEM_Q3600_LPF 1350 -#define MODEM_Q3600_BPF_TAP 256 -#define MODEM_Q3600_LPF_TAP 128 - // -#define MODEM_Q4800_BPF 4800 -#define MODEM_Q4800_TXBPF 5000 -#define MODEM_Q4800_LPF 1800 -#define MODEM_Q4800_BPF_TAP 256 -#define MODEM_Q4800_LPF_TAP 128 - // -#define MODEM_P2400_BPF 4800 -#define MODEM_P2400_TXBPF 5000 -#define MODEM_P2400_LPF 1800 -#define MODEM_P2400_BPF_TAP 256 -#define MODEM_P2400_LPF_TAP 128 - // -#define MODEM_P1200_BPF 2400 -#define MODEM_P1200_TXBPF 2500 -#define MODEM_P1200_LPF 900 -#define MODEM_P1200_BPF_TAP 256 -#define MODEM_P1200_LPF_TAP 128 - // -#define MODEM_P600_BPF 1200 -#define MODEM_P600_TXBPF 1250 -#define MODEM_P600_LPF 400 -#define MODEM_P600_BPF_TAP 256 -#define MODEM_P600_LPF_TAP 128 - // -#define MODEM_P300_BPF 600 -#define MODEM_P300_TXBPF 625 -#define MODEM_P300_LPF 200 -#define MODEM_P300_BPF_TAP 256 -#define MODEM_P300_LPF_TAP 128 - // -#define MODEM_300_BPF 500 -#define MODEM_300_TXBPF 500 -#define MODEM_300_LPF 155 -#define MODEM_300_BPF_TAP 256 -#define MODEM_300_LPF_TAP 128 - // -#define MODEM_600_BPF 800 -#define MODEM_600_TXBPF 900 -#define MODEM_600_LPF 325 -#define MODEM_600_BPF_TAP 256 -#define MODEM_600_LPF_TAP 128 - // -#define MODEM_1200_BPF 1400 -#define MODEM_1200_TXBPF 1600 -#define MODEM_1200_LPF 650 -#define MODEM_1200_BPF_TAP 256 -#define MODEM_1200_LPF_TAP 128 - // -#define MODEM_2400_BPF 3200 -#define MODEM_2400_TXBPF 3200 -#define MODEM_2400_LPF 1400 -#define MODEM_2400_BPF_TAP 256 -#define MODEM_2400_LPF_TAP 128 - -#define TX_SILENCE 0 -#define TX_DELAY 1 -#define TX_TAIL 2 -#define TX_NO_DATA 3 -#define TX_FRAME 4 -#define TX_WAIT_BPF 5 - - -#define FRAME_WAIT 0 -#define FRAME_LOAD 1 -#define RX_BIT0 0 -#define RX_BIT1 128 -#define DCD_WAIT_SLOT 0 -#define DCD_WAIT_PERSIST 1 - -#define FX25_MODE_NONE 0 -#define FX25_MODE_RX 1 -#define FX25_MODE_TXRX 2 -#define FX25_TAG 0 -#define FX25_LOAD 1 - -#define IL2P_MODE_NONE 0 -#define IL2P_MODE_RX 1 // RX il2p + HDLC -#define IL2P_MODE_TXRX 2 -#define IL2P_MODE_ONLY 3 // RX only il2p, TX il2p - - -#define MODE_OUR 0 -#define MODE_OTHER 1 -#define MODE_RETRY 2 - -#define FRAME_FLAG 126 // 7e - -#define port_num 32 // ?? Max AGW sessions -#define PKT_ERR 17 // Minimum packet size, bytes -#define I_MAX 7 // Maximum number of packets - - - // externs for all modules - -#define ARDOPBufferSize 12000 * 100 - -extern short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples - -extern int ARDOPTXLen[4]; // Length of frame -extern int ARDOPTXPtr[4]; // Tx Pointer - -extern BOOL KISSServ; -extern int KISSPort; - -extern BOOL AGWServ; -extern int AGWPort; - -extern TStringList KISS_acked[]; -extern TStringList KISS_iacked[]; - -extern TStringList all_frame_buf[5]; - -extern unsigned short pkt_raw_min_len; -extern int stat_r_mem; - -extern UCHAR diddles; - -extern int stdtones; -extern int fullduplex; - -extern struct TQPSK_t qpsk_set[4]; - -extern int NonAX25[5]; - -extern short txtail[5]; -extern short txdelay[5]; - -extern short modem_def[5]; - -extern int emph_db[5]; -extern UCHAR emph_all[5]; - -extern UCHAR modem_mode[5]; - -extern UCHAR RCVR[5]; -extern int soundChannel[5]; -extern int modemtoSoundLR[4]; - -extern short rx_freq[5]; -extern short rx_shift[5]; -extern short rx_baudrate[5]; -extern short rcvr_offset[5]; - -extern int tx_hitoneraisedb[5]; -extern float tx_hitoneraise[5]; - - -extern UCHAR tx_status[5]; -extern float tx_freq[5]; -extern float tx_shift[5]; -extern unsigned short tx_baudrate[5]; - -extern unsigned short bpf[5]; -extern unsigned short lpf[5]; - -extern unsigned short txbpf[5]; - -extern unsigned short tx_BPF_tap[5]; -extern unsigned short tx_BPF_timer[5]; - -extern unsigned short BPF_tap[5]; -extern unsigned short LPF_tap[5]; - -extern float tx_BPF_core[5][32768]; -extern float LPF_core[5][2048]; - -extern UCHAR xData[256]; -extern UCHAR xEncoded[256]; -extern UCHAR xDecoded[256]; - -extern float PI125; -extern float PI375; -extern float PI625; -extern float PI875; -extern float PI5; -extern float PI25; -extern float PI75; - -extern int max_frame_collector[4]; -extern boolean KISS_opt[4]; - -#define MaxErrors 4 - -extern BOOL MinOnStart; - -//RS TReedSolomon; -// Form1 TForm1; -// WaveFormat TWaveFormatEx; - -extern int UDPServ; -extern long long udpServerSeqno; - -extern int Channels; -extern int BitsPerSample; -extern float TX_Samplerate; -extern float RX_Samplerate; -extern int RX_SR; -extern int TX_SR; -extern int RX_PPM; -extern int TX_PPM; -extern int tx_bufsize; -extern int rx_bufsize; -extern int tx_bufcount; -extern int rx_bufcount; -extern int fft_size; -extern int mouse_down[2]; -//UCHAR * RX_pBuf array[257]; -// RX_header array[1..256] of TWaveHdr; -// TX_pBuf array[1..4,1..256] of pointer; -//TX_header array[1..4,1..256] of TWaveHdr; -extern UCHAR calib_mode[5]; -extern UCHAR snd_status[5]; -extern UCHAR buf_status[5]; -extern UCHAR tx_buf_num1[5]; -extern UCHAR tx_buf_num[5]; -extern int speed[5]; -extern int panels[6]; - -extern int FFTSize; -#define fft_size FFTSize - -extern float fft_window_arr[2048]; -// fft_s,fft_d array[0..2047] of TComplex; -extern short fft_buf[5][4096]; -extern UCHAR fft_disp[5][4096]; -// bm array[1..4] of TBitMap; -// bm1,bm2,bm3 TBitMap; - -// WaveInHandle hWaveIn; -// WaveOutHandle array[1..4] of hWaveOut; -extern int RXBufferLength; - -// data1 PData16; - -extern int grid_time; -extern int fft_mult; -extern int fft_spd; -extern int grid_timer; -extern int stop_wf; -extern int raduga; -extern char snd_rx_device_name[32]; -extern char snd_tx_device_name[32]; -extern int snd_rx_device; -extern int snd_tx_device; -extern UCHAR mod_icon_status; -extern UCHAR last_mod_icon_status; -extern UCHAR icon_timer; -// TelIni TIniFile; -extern char cur_dir[]; -// TimerId1 cardinal; -// TimerId2 cardinal; -extern UCHAR TimerStat1; -extern UCHAR TimerStat2; -extern int stat_log; - -extern char PTTPort[80]; // Port for Hardware PTT - may be same as control port. -extern int PTTMode; -extern int PTTBAUD ; - -extern char PTTOnString[128]; -extern char PTTOffString[128]; - -extern UCHAR PTTOnCmd[64]; -extern UCHAR PTTOnCmdLen; - -extern UCHAR PTTOffCmd[64]; -extern UCHAR PTTOffCmdLen; - -extern int PTT_device; -extern int RX_device; -extern int TX_device; -extern int TX_rotate; -extern int UsingLeft; -extern int UsingRight; -extern int UsingBothChannels; -extern int pttGPIOPin; -extern int pttGPIOPinR; -extern BOOL pttGPIOInvert; -extern BOOL useGPIO; -extern BOOL gotGPIO; -extern int VID; -extern int PID; -extern char CM108Addr[80]; -extern int HamLibPort; -extern char HamLibHost[]; - -extern int SCO; -extern int DualPTT; -extern UCHAR DebugMode; -extern UCHAR TimerEvent; -extern int nr_monitor_lines; -extern int UTC_Tim; -extern int MainPriority; -// MainThreadHandle THandle; -extern UCHAR w_state; - -extern BOOL Firstwaterfall; -extern BOOL Secondwaterfall; - -extern int dcd_threshold; -extern int rxOffset; -extern int chanOffset[4]; - -extern boolean busy; -extern boolean dcd[5]; - -extern struct TKISSMode_t KISS; - -extern boolean dyn_frack[4] ; -extern Byte recovery[4]; -extern Byte users[4]; - -extern int resptime[4]; -extern int slottime[4]; -extern int persist[4]; -extern int fracks[4]; -extern int frack_time[4]; -extern int idletime[4]; -extern int redtime[4]; -extern int IPOLL[4]; -extern int maxframe[4]; -extern int TXFrmMode[4]; - -extern char MyDigiCall[4][512]; -extern char exclude_callsigns[4][512]; -extern char exclude_APRS_frm[4][512]; - -extern TStringList list_exclude_callsigns[4]; -extern TStringList list_exclude_APRS_frm[4]; -extern TStringList list_digi_callsigns[4]; - - -extern int SoundIsPlaying; -extern int Capturing; - -extern struct TDetector_t DET[nr_emph + 1][16]; - -extern char CaptureDevice[80]; -extern char PlaybackDevice[80]; - -extern TAX25Port AX25Port[4][port_num]; - -extern int fx25_mode[4]; -extern int il2p_mode[4]; - -extern int tx_fx25_size[4]; -extern int tx_fx25_size_cnt[4]; -extern int tx_fx25_mode[4]; - -extern int SatelliteMode; - -// Function prototypes - -void KISS_send_ack(UCHAR port, string * data); -void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame); -void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev); -void make_core_TXBPF(UCHAR snd_ch, float freq, float width); -void OpenPTTPort(); -void ClosePTTPort(); - -void RadioPTT(int snd_ch, BOOL PTTState); -void put_frame(int snd_ch, string * frame, char * code, int tx_stat, int excluded); -void CloseCOMPort(int fd); -void COMClearRTS(int fd); -void COMClearDTR(int fd); -unsigned int getTicks(); -char * ShortDateTime(); -void write_ax25_info(TAX25Port * AX25Sess); -void reverse_addr(Byte * path, Byte * revpath, int Len); -string * get_mycall(string * path); -TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); -TAX25Port * get_free_port(int snd_ch); -void * in_list_incoming_mycall(Byte * path); -boolean add_incoming_mycalls(void * socket, char * src_call); -int get_addr(char * Calls, UCHAR * AXCalls); -void reverse_addr(Byte * path, Byte * revpath, int Len); -void set_link(TAX25Port * AX25Sess, UCHAR * axpath); -void rst_timer(TAX25Port * AX25Sess); -void set_unlink(TAX25Port * AX25Sess, Byte * path); -unsigned short get_fcs(UCHAR * Data, unsigned short len); -void KISSSendtoServer(void * sock, Byte * Msg, int Len); -int ConvFromAX25(unsigned char * incall, char * outcall); -BOOL ConvToAX25(char * callsign, unsigned char * ax25call); -void Debugprintf(const char * format, ...); - -double pila(double x); - -void AGW_Raw_monitor(int snd_ch, string * data); - -// Dephi emulation functions - -string * Strings(TStringList * Q, int Index); -void Clear(TStringList * Q); -int Count(TStringList * List); - -string * newString(); -string * copy(string * Source, int StartChar, int Count); -TStringList * newTStringList(); - -void freeString(string * Msg); - -void initString(string * S); -void initTStringList(TStringList* T); - -// Two delete() This is confusing!! -// Not really - one acts on String, other TStringList - -void Delete(TStringList * Q, int Index); -void mydelete(string * Source, int StartChar, int Count); - -void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); -void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); - -void setlength(string * Msg, int Count); // Set string length - -string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string - -void Assign(TStringList * to, TStringList * from); // Duplicate from to to - -string * duplicateString(string * in); - -// This looks for a string in a stringlist. Returns inhex if found, otherwise -1 - -int my_indexof(TStringList * l, string * s); - -boolean compareStrings(string * a, string * b); - -int Add(TStringList * Q, string * Entry); -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/debian/install b/debian/install index db69a5c..badbb26 100644 --- a/debian/install +++ b/debian/install @@ -1,3 +1,3 @@ -QtSoundModem /usr/bin/qtsoundmodem +QtSoundModem /usr/bin debian/qtsoundmodem.desktop /usr/share/applications debian/QtSoundModem.png /usr/share/pixmaps diff --git a/debian/qtsoundmodem.desktop b/debian/qtsoundmodem.desktop index ae3e609..7ad2f91 100644 --- a/debian/qtsoundmodem.desktop +++ b/debian/qtsoundmodem.desktop @@ -2,7 +2,7 @@ Name=QtSoundModem Comment=QtSoundModem Version=1.0 -Exec=/usr/bin/qtsoundmodem +Exec=/usr/bin/QtSoundModem GenericName=QtSoundModem Icon=QtSoundModem NoDisplay=false diff --git a/il2p.c.bak b/il2p.c.bak deleted file mode 100644 index 2c81201..0000000 --- a/il2p.c.bak +++ /dev/null @@ -1,4502 +0,0 @@ -/* -Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO - -This file is part of QtSoundModem - -QtSoundModem 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. - -QtSoundModem 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 QtSoundModem. If not, see http://www.gnu.org/licenses - -*/ - -// UZ7HO Soundmodem Port by John Wiseman G8BPQ - -// IL2P code. Based on Direwolf code, under the following copyright - -// -// Copyright (C) 2021 John Langner, WB2OSZ -// -// 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, see . -// - - -// IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders - - - - -#include "UZ7HOStuff.h" - -void Debugprintf(const char * format, ...); - -#define MAX_ADEVS 3 - -#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2) - -#define MAX_CHANS MAX_RADIO_CHANS // TODO: Replace all former with latter to avoid confusion with following. - -#define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected - // to something other than radio modems. - // Total maximum channels is based on the 4 bit KISS field. - // Someone with very unusual requirements could increase this and - // use only the AGW network protocol. - - -#define MAX_SUBCHANS 9 - -#define MAX_SLICERS 9 - -#define max(x, y) ((x) > (y) ? (x) : (y)) -#define min(x, y) ((x) < (y) ? (x) : (y)) - -/* For option to try fixing frames with bad CRC. */ - -typedef enum retry_e { - RETRY_NONE = 0, - RETRY_INVERT_SINGLE = 1, - RETRY_INVERT_DOUBLE = 2, - RETRY_INVERT_TRIPLE = 3, - RETRY_INVERT_TWO_SEP = 4, - RETRY_MAX = 5 -} retry_t; - -typedef struct alevel_s { - int rec; - int mark; - int space; - //float ms_ratio; // TODO: take out after temporary investigation. -} alevel_t; - - -alevel_t demod_get_audio_level(int chan, int subchan); -void tone_gen_put_bit(int chan, int dat); - -int ax25memdebug = 1; - -// Code to try to determine centre freq - -float MagOut[4096]; -float MaxMagOut = 0; -int MaxMagIndex = 0; - -// FFT Bin Size is 12000 / FFTSize - -#ifndef FX25_H -#define FX25_H - -#include // for uint64_t - - -/* Reed-Solomon codec control block */ -struct rs { - unsigned int mm; /* Bits per symbol */ - unsigned int nn; /* Symbols per block (= (1<mm) -#define NN (rs->nn) -#define ALPHA_TO (rs->alpha_to) -#define INDEX_OF (rs->index_of) -#define GENPOLY (rs->genpoly) -#define NROOTS (rs->nroots) -#define FCR (rs->fcr) -#define PRIM (rs->prim) -#define IPRIM (rs->iprim) -#define A0 (NN) - -int __builtin_popcountll(unsigned long long int i) -{ - return 0; -} - -int __builtin_popcount(unsigned int n) -{ - unsigned int count = 0; - while (n) - { - count += n & 1; - n >>= 1; - } - return count; -} - -static inline int modnn(struct rs *rs, int x) { - while (x >= rs->nn) { - x -= rs->nn; - x = (x >> rs->mm) + (x & rs->nn); - } - return x; -} - -#define MODNN(x) modnn(rs,x) - - -#define ENCODE_RS encode_rs_char -#define DECODE_RS decode_rs_char -#define INIT_RS init_rs_char -#define FREE_RS free_rs_char - -#define DTYPE unsigned char - -void ENCODE_RS(struct rs *rs, DTYPE *data, DTYPE *bb); - -int DECODE_RS(struct rs *rs, DTYPE *data, int *eras_pos, int no_eras); - -struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, - unsigned int fcr, unsigned int prim, unsigned int nroots); - -void FREE_RS(struct rs *rs); - - - -// These 3 are the external interface. -// Maybe these should be in a different file, separated from the internal stuff. - -void fx25_init(int debug_level); -int fx25_send_frame(int chan, unsigned char *fbuf, int flen, int fx_mode); -void fx25_rec_bit(int chan, int subchan, int slice, int dbit); -int fx25_rec_busy(int chan); - - -// Other functions in fx25_init.c. - -struct rs *fx25_get_rs(int ctag_num); -uint64_t fx25_get_ctag_value(int ctag_num); -int fx25_get_k_data_radio(int ctag_num); -int fx25_get_k_data_rs(int ctag_num); -int fx25_get_nroots(int ctag_num); -int fx25_get_debug(void); -int fx25_tag_find_match(uint64_t t); -int fx25_pick_mode(int fx_mode, int dlen); - -void fx_hex_dump(unsigned char *x, int len); - -/*------------------------------------------------------------------- - * - * Name: ax25_pad.h - * - * Purpose: Header file for using ax25_pad.c - * - *------------------------------------------------------------------*/ - -#ifndef AX25_PAD_H -#define AX25_PAD_H 1 - - -#define AX25_MAX_REPEATERS 8 -#define AX25_MIN_ADDRS 2 /* Destination & Source. */ -#define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */ - -#define AX25_DESTINATION 0 /* Address positions in frame. */ -#define AX25_SOURCE 1 -#define AX25_REPEATER_1 2 -#define AX25_REPEATER_2 3 -#define AX25_REPEATER_3 4 -#define AX25_REPEATER_4 5 -#define AX25_REPEATER_5 6 -#define AX25_REPEATER_6 7 -#define AX25_REPEATER_7 8 -#define AX25_REPEATER_8 9 - -#define AX25_MAX_ADDR_LEN 12 /* In theory, you would expect the maximum length */ - /* to be 6 letters, dash, 2 digits, and nul for a */ - /* total of 10. However, object labels can be 10 */ - /* characters so throw in a couple extra bytes */ - /* to be safe. */ - -#define AX25_MIN_INFO_LEN 0 /* Previously 1 when considering only APRS. */ - -#define AX25_MAX_INFO_LEN 2048 /* Maximum size for APRS. */ - /* AX.25 starts out with 256 as the default max */ - /* length but the end stations can negotiate */ - /* something different. */ - /* version 0.8: Change from 256 to 2028 to */ - /* handle the larger paclen for Linux AX25. */ - - /* These don't include the 2 bytes for the */ - /* HDLC frame FCS. */ - -/* - * Previously, for APRS only. - * #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN) - * #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN) - */ - - /* The more general case. */ - /* An AX.25 frame can have a control byte and no protocol. */ - -#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 ) - -#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN) - - -/* - * packet_t is a pointer to a packet object. - * - * The actual implementation is not visible outside ax25_pad.c. - */ - -#define AX25_UI_FRAME 3 /* Control field value. */ - -#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */ -#define AX25_PID_SEGMENTATION_FRAGMENT 0x08 -#define AX25_PID_ESCAPE_CHARACTER 0xff - -struct packet_s { - - int magic1; /* for error checking. */ - - int seq; /* unique sequence number for debugging. */ - - double release_time; /* Time stamp in format returned by dtime_now(). */ - /* When to release from the SATgate mode delay queue. */ - -#define MAGIC 0x41583235 - - struct packet_s *nextp; /* Pointer to next in queue. */ - - int num_addr; /* Number of addresses in frame. */ - /* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */ - /* It will be 0 if it doesn't look like AX.25. */ - /* -1 is used temporarily at allocation to mean */ - /* not determined yet. */ - - - - /* - * The 7th octet of each address contains: - * - * Bits: H R R SSID 0 - * - * H for digipeaters set to 0 initially. - * Changed to 1 when position has been used. - * - * for source & destination it is called - * command/response. Normally both 1 for APRS. - * They should be opposites for connected mode. - * - * R R Reserved. Normally set to 1 1. - * - * SSID Substation ID. Range of 0 - 15. - * - * 0 Usually 0 but 1 for last address. - */ - - -#define SSID_H_MASK 0x80 -#define SSID_H_SHIFT 7 - -#define SSID_RR_MASK 0x60 -#define SSID_RR_SHIFT 5 - -#define SSID_SSID_MASK 0x1e -#define SSID_SSID_SHIFT 1 - -#define SSID_LAST_MASK 0x01 - - - int frame_len; /* Frame length without CRC. */ - - int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */ - /* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */ - /* control bytes. Unfortunately, we can't determine this by looking */ - /* at an isolated frame. We need to know about the context. If we */ - /* are part of the conversation, we would know. But if we are */ - /* just listening to others, this would be more difficult to determine. */ - - /* For U frames: set to 0 - not applicable */ - /* For I & S frames: 8 or 128 if known. 0 if unknown. */ - - unsigned char frame_data[AX25_MAX_PACKET_LEN + 1]; - /* Raw frame contents, without the CRC. */ - - - int magic2; /* Will get stomped on if above overflows. */ -}; - - - -typedef struct packet_s *packet_t; - -typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t; - - -extern packet_t ax25_new(void); - - -#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */ - - -/* - * APRS always has one control octet of 0x03 but the more - * general AX.25 case is one or two control bytes depending on - * whether "modulo 128 operation" is in effect. - */ - - //#define DEBUGX 1 - -static inline int ax25_get_control_offset(packet_t this_p) -{ - return (this_p->num_addr * 7); -} - -static inline int ax25_get_num_control(packet_t this_p) -{ - int c; - - c = this_p->frame_data[ax25_get_control_offset(this_p)]; - - if ((c & 0x01) == 0) { /* I xxxx xxx0 */ -#if DEBUGX - Debugprintf("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); -#endif - return ((this_p->modulo == 128) ? 2 : 1); - } - - if ((c & 0x03) == 1) { /* S xxxx xx01 */ -#if DEBUGX - Debugprintf("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); -#endif - return ((this_p->modulo == 128) ? 2 : 1); - } - -#if DEBUGX - Debugprintf("ax25_get_num_control, %02x is U frame, always returns 1.\n", c); -#endif - - return (1); /* U xxxx xx11 */ -} - - - -/* - * APRS always has one protocol octet of 0xF0 meaning no level 3 - * protocol but the more general case is 0, 1 or 2 protocol ID octets. - */ - -static inline int ax25_get_pid_offset(packet_t this_p) -{ - return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); -} - -static int ax25_get_num_pid(packet_t this_p) -{ - int c; - int pid; - - c = this_p->frame_data[ax25_get_control_offset(this_p)]; - - if ((c & 0x01) == 0 || /* I xxxx xxx0 */ - c == 0x03 || c == 0x13) { /* UI 000x 0011 */ - - pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; -#if DEBUGX - Debugprintf("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid == AX25_PID_ESCAPE_CHARACTER) ? 2 : 1); -#endif - if (pid == AX25_PID_ESCAPE_CHARACTER) { - return (2); /* pid 1111 1111 means another follows. */ - } - return (1); - } -#if DEBUGX - Debugprintf("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c); -#endif - return (0); -} - - -/* - * AX.25 has info field for 5 frame types depending on the control field. - * - * xxxx xxx0 I - * 000x 0011 UI (which includes APRS) - * 101x 1111 XID - * 111x 0011 TEST - * 100x 0111 FRMR - * - * APRS always has an Information field with at least one octet for the Data Type Indicator. - */ - -static inline int ax25_get_info_offset(packet_t this_p) -{ - int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); -#if DEBUGX - Debugprintf("ax25_get_info_offset, returns %d\n", offset); -#endif - return (offset); -} - -static inline int ax25_get_num_info(packet_t this_p) -{ - int len; - - /* assuming AX.25 frame. */ - - len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); - if (len < 0) { - len = 0; /* print error? */ - } - - return (len); -} - -#endif - - -typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t; - -typedef enum ax25_frame_type_e { - - frame_type_I = 0, // Information - - frame_type_S_RR, // Receive Ready - System Ready To Receive - frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full - frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate - frame_type_S_SREJ, // Selective Reject - Request single frame repeat - - frame_type_U_SABME, // Set Async Balanced Mode, Extended - frame_type_U_SABM, // Set Async Balanced Mode - frame_type_U_DISC, // Disconnect - frame_type_U_DM, // Disconnect Mode - frame_type_U_UA, // Unnumbered Acknowledge - frame_type_U_FRMR, // Frame Reject - frame_type_U_UI, // Unnumbered Information - frame_type_U_XID, // Exchange Identification - frame_type_U_TEST, // Test - frame_type_U, // other Unnumbered, not used by AX.25. - - frame_not_AX25 // Could not get control byte from frame. - // This must be last because value plus 1 is - // for the size of an array. - -} ax25_frame_type_t; - - -/* - * Originally this was a single number. - * Let's try something new in version 1.2. - * Also collect AGC values from the mark and space filters. - */ - -#ifndef AXTEST -// TODO: remove this? -#define AX25MEMDEBUG 1 -#endif - - - -extern packet_t ax25_from_text(char *monitor, int strict); - -extern packet_t ax25_from_frame(unsigned char *data, int len, alevel_t alevel); - -extern packet_t ax25_dup(packet_t copy_from); - -extern void ax25_delete(packet_t pp); - - - -extern int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard); -extern int ax25_check_addresses(packet_t pp); - -extern packet_t ax25_unwrap_third_party(packet_t from_pp); - -extern void ax25_set_addr(packet_t pp, int, char *); -extern void ax25_insert_addr(packet_t this_p, int n, char *ad); -extern void ax25_remove_addr(packet_t this_p, int n); - -extern int ax25_get_num_addr(packet_t pp); -extern int ax25_get_num_repeaters(packet_t this_p); - -extern void ax25_get_addr_with_ssid(packet_t pp, int n, char *station); -extern void ax25_get_addr_no_ssid(packet_t pp, int n, char *station); - -extern int ax25_get_ssid(packet_t pp, int n); -extern void ax25_set_ssid(packet_t this_p, int n, int ssid); - -extern int ax25_get_h(packet_t pp, int n); - -extern void ax25_set_h(packet_t pp, int n); - -extern int ax25_get_heard(packet_t this_p); - -extern int ax25_get_first_not_repeated(packet_t pp); - -extern int ax25_get_rr(packet_t this_p, int n); - -extern int ax25_get_info(packet_t pp, unsigned char **paddr); -extern void ax25_set_info(packet_t pp, unsigned char *info_ptr, int info_len); -extern int ax25_cut_at_crlf(packet_t this_p); - -extern void ax25_set_nextp(packet_t this_p, packet_t next_p); - -extern int ax25_get_dti(packet_t this_p); - -extern packet_t ax25_get_nextp(packet_t this_p); - -extern void ax25_set_release_time(packet_t this_p, double release_time); -extern double ax25_get_release_time(packet_t this_p); - -extern void ax25_set_modulo(packet_t this_p, int modulo); -extern int ax25_get_modulo(packet_t this_p); - -extern void ax25_format_addrs(packet_t pp, char *); -extern void ax25_format_via_path(packet_t this_p, char *result, size_t result_size); - -extern int ax25_pack(packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]); - -extern ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns); - -extern void ax25_hex_dump(packet_t this_p); - -extern int ax25_is_aprs(packet_t pp); -extern int ax25_is_null_frame(packet_t this_p); - -extern int ax25_get_control(packet_t this_p); -extern int ax25_get_c2(packet_t this_p); - -extern int ax25_get_pid(packet_t this_p); - -extern int ax25_get_frame_len(packet_t this_p); -extern unsigned char *ax25_get_frame_data_ptr(packet_t this_p); - -extern unsigned short ax25_dedupe_crc(packet_t pp); - -extern unsigned short ax25_m_m_crc(packet_t pp); - -extern void ax25_safe_print(char *, int, int ascii_only); - -#define AX25_ALEVEL_TO_TEXT_SIZE 40 // overkill but safe. -extern int ax25_alevel_to_text(alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]); - - -#endif /* AX25_PAD_H */ - -/* end ax25_pad.h */ - - - - -#define CTAG_MIN 0x01 -#define CTAG_MAX 0x0B - -// Maximum sizes of "data" and "check" parts. - -#define FX25_MAX_DATA 239 // i.e. RS(255,239) -#define FX25_MAX_CHECK 64 // e.g. RS(255, 191) -#define FX25_BLOCK_SIZE 255 // Block size always 255 for 8 bit symbols. - -#endif // FX25_H - -#ifndef IL2P_H -#define IL2P_H 1 - - -#define IL2P_PREAMBLE 0x55 - -#define IL2P_SYNC_WORD 0xF15E48 - -#define IL2P_SYNC_WORD_SIZE 3 -#define IL2P_HEADER_SIZE 13 // Does not include 2 parity. -#define IL2P_HEADER_PARITY 2 - -#define IL2P_MAX_PAYLOAD_SIZE 1023 -#define IL2P_MAX_PAYLOAD_BLOCKS 5 -#define IL2P_MAX_PARITY_SYMBOLS 16 // For payload only. -#define IL2P_MAX_ENCODED_PAYLOAD_SIZE (IL2P_MAX_PAYLOAD_SIZE + IL2P_MAX_PAYLOAD_BLOCKS * IL2P_MAX_PARITY_SYMBOLS) - -#define IL2P_MAX_PACKET_SIZE (IL2P_SYNC_WORD_SIZE + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY + IL2P_MAX_ENCODED_PAYLOAD_SIZE) - - -float GuessCentreFreq(int i) -{ - float Freq = 0; - float Start; - float End; - int n; - float Max = 0; - int Index = 0; - - Start = (rx_freq[i] - RCVR[i] * rcvr_offset[i]) / BinSize; - End = (rx_freq[i] + RCVR[i] * rcvr_offset[i]) / BinSize; - - for (n = Start; n <= End; n++) - { - if (MagOut[n] > Max) - { - Max = MagOut[n]; - Index = n; - } - } - - Freq = Index * BinSize; - - return Freq; -} - -/*------------------------------------------------------------------------------ - * - * Name: ax25_new - * - * Purpose: Allocate memory for a new packet object. - * - * Returns: Identifier for a new packet object. - * In the current implementation this happens to be a pointer. - * - *------------------------------------------------------------------------------*/ - -int last_seq_num = 0; -int new_count = 0; -int delete_count = 0; - -packet_t ax25_new(void) -{ - struct packet_s *this_p; - - -#if DEBUG - text_color_set(DW_COLOR_DEBUG); - Debugprintf("ax25_new(): before alloc, new=%d, delete=%d\n", new_count, delete_count); -#endif - - last_seq_num++; - new_count++; - - /* - * check for memory leak. - */ - - // version 1.4 push up the threshold. We could have considerably more with connected mode. - - //if (new_count > delete_count + 100) { - if (new_count > delete_count + 256) { - - Debugprintf("Report to WB2OSZ - Memory leak for packet objects. new=%d, delete=%d\n", new_count, delete_count); -#if AX25MEMDEBUG -#endif - } - - this_p = calloc(sizeof(struct packet_s), (size_t)1); - - if (this_p == NULL) { - Debugprintf("ERROR - can't allocate memory in ax25_new.\n"); - } - -// assert(this_p != NULL); - - this_p->magic1 = MAGIC; - this_p->seq = last_seq_num; - this_p->magic2 = MAGIC; - this_p->num_addr = (-1); - - return (this_p); -} - -/*------------------------------------------------------------------------------ - * - * Name: ax25_delete - * - * Purpose: Destroy a packet object, freeing up memory it was using. - * - *------------------------------------------------------------------------------*/ - -void ax25_delete(packet_t this_p) -{ - if (this_p == NULL) { - Debugprintf("ERROR - NULL pointer passed to ax25_delete.\n"); - return; - } - - delete_count++; - -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - this_p->magic1 = 0; - this_p->magic1 = 0; - - free(this_p); -} - - - - - -/*------------------------------------------------------------------------------ - * - * Name: ax25_s_frame - * - * Purpose: Construct an S frame. - * - * Input: addrs - Array of addresses. - * - * num_addr - Number of addresses, range 2 .. 10. - * - * cr - cr_cmd command frame, cr_res for a response frame. - * - * ftype - One of: - * frame_type_S_RR, // Receive Ready - System Ready To Receive - * frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full - * frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate - * frame_type_S_SREJ, // Selective Reject - Request single frame repeat - * - * modulo - 8 or 128. Determines if we have 1 or 2 control bytes. - * - * nr - N(R) field --- describe. - * - * pf - Poll/Final flag. - * - * pinfo - Pointer to data for Info field. Allowed only for SREJ. - * - * info_len - Length for Info field. - * - * - * Returns: Pointer to new packet object. - * - *------------------------------------------------------------------------------*/ - - -packet_t ax25_s_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len) -{ - packet_t this_p; - unsigned char *p; - int ctrl = 0; - - this_p = ax25_new(); - - if (this_p == NULL) return (NULL); - - if (!set_addrs(this_p, addrs, num_addr, cr)) { - Debugprintf("Internal error in %s: Could not set addresses for S frame.\n", __func__); - ax25_delete(this_p); - return (NULL); - } - - if (modulo != 8 && modulo != 128) { - Debugprintf("Internal error in %s: Invalid modulo %d for S frame.\n", __func__, modulo); - modulo = 8; - } - this_p->modulo = modulo; - - if (nr < 0 || nr >= modulo) { - Debugprintf("Internal error in %s: Invalid N(R) %d for S frame.\n", __func__, nr); - nr &= (modulo - 1); - } - - // Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both. - // The underlying X.25 spec clearly says it is response only. Let's go with that. - - if (ftype == frame_type_S_SREJ && cr != cr_res) { - Debugprintf("Internal error in %s: SREJ must be response.\n", __func__); - } - - switch (ftype) { - - case frame_type_S_RR: ctrl = 0x01; break; - case frame_type_S_RNR: ctrl = 0x05; break; - case frame_type_S_REJ: ctrl = 0x09; break; - case frame_type_S_SREJ: ctrl = 0x0d; break; - - default: - Debugprintf("Internal error in %s: Invalid ftype %d for S frame.\n", __func__, ftype); - ax25_delete(this_p); - return (NULL); - break; - } - - p = this_p->frame_data + this_p->frame_len; - - if (modulo == 8) { - if (pf) ctrl |= 0x10; - ctrl |= nr << 5; - *p++ = ctrl; - this_p->frame_len++; - } - else { - *p++ = ctrl; - this_p->frame_len++; - - ctrl = pf & 1; - ctrl |= nr << 1; - *p++ = ctrl; - this_p->frame_len++; - } - - if (ftype == frame_type_S_SREJ) { - if (pinfo != NULL && info_len > 0) { - if (info_len > AX25_MAX_INFO_LEN) { - Debugprintf("Internal error in %s: SREJ frame, Invalid information field length %d.\n", __func__, info_len); - info_len = AX25_MAX_INFO_LEN; - } - memcpy(p, pinfo, info_len); - p += info_len; - this_p->frame_len += info_len; - } - } - else { - if (pinfo != NULL || info_len != 0) { - Debugprintf("Internal error in %s: Info part not allowed for RR, RNR, REJ frame.\n", __func__); - } - } - *p = '\0'; - - - return (this_p); - -} /* end ax25_s_frame */ - - - - - -/*------------------------------------------------------------------------------ - * - * Name: ax25_i_frame - * - * Purpose: Construct an I frame. - * - * Input: addrs - Array of addresses. - * - * num_addr - Number of addresses, range 2 .. 10. - * - * cr - cr_cmd command frame, cr_res for a response frame. - * - * modulo - 8 or 128. - * - * nr - N(R) field --- describe. - * - * ns - N(S) field --- describe. - * - * pf - Poll/Final flag. - * - * pid - Protocol ID. - * Normally 0xf0 meaning no level 3. - * Could be other values for NET/ROM, etc. - * - * pinfo - Pointer to data for Info field. - * - * info_len - Length for Info field. - * - * - * Returns: Pointer to new packet object. - * - *------------------------------------------------------------------------------*/ - -packet_t ax25_i_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len) -{ - packet_t this_p; - unsigned char *p; - int ctrl = 0; - - this_p = ax25_new(); - - if (this_p == NULL) return (NULL); - - if (!set_addrs(this_p, addrs, num_addr, cr)) { - Debugprintf("Internal error in %s: Could not set addresses for I frame.\n", __func__); - ax25_delete(this_p); - return (NULL); - } - - if (modulo != 8 && modulo != 128) { - Debugprintf("Internal error in %s: Invalid modulo %d for I frame.\n", __func__, modulo); - modulo = 8; - } - this_p->modulo = modulo; - - if (nr < 0 || nr >= modulo) { - Debugprintf("Internal error in %s: Invalid N(R) %d for I frame.\n", __func__, nr); - nr &= (modulo - 1); - } - - if (ns < 0 || ns >= modulo) { - Debugprintf("Internal error in %s: Invalid N(S) %d for I frame.\n", __func__, ns); - ns &= (modulo - 1); - } - - p = this_p->frame_data + this_p->frame_len; - - if (modulo == 8) { - ctrl = (nr << 5) | (ns << 1); - if (pf) ctrl |= 0x10; - *p++ = ctrl; - this_p->frame_len++; - } - else { - ctrl = ns << 1; - *p++ = ctrl; - this_p->frame_len++; - - ctrl = nr << 1; - if (pf) ctrl |= 0x01; - *p++ = ctrl; - this_p->frame_len++; - } - - // Definitely don't want pid value of 0 (not in valid list) - // or 0xff (which means more bytes follow). - - if (pid < 0 || pid == 0 || pid == 0xff) { - Debugprintf("Warning: Client application provided invalid PID value, 0x%02x, for I frame.\n", pid); - pid = AX25_PID_NO_LAYER_3; - } - *p++ = pid; - this_p->frame_len++; - - if (pinfo != NULL && info_len > 0) { - if (info_len > AX25_MAX_INFO_LEN) { - Debugprintf("Internal error in %s: I frame, Invalid information field length %d.\n", __func__, info_len); - info_len = AX25_MAX_INFO_LEN; - } - memcpy(p, pinfo, info_len); - p += info_len; - this_p->frame_len += info_len; - } - - *p = '\0'; - - - return (this_p); - -} /* end ax25_i_frame */ - - - - - -extern TStringList detect_list[5]; -extern TStringList detect_list_c[5]; - -void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25, int emph, int centreFreq) -{ - // Convert to QtSM internal format - - struct TDetector_t * pDET = &DET[emph][subchan]; - string * data = newString(); - char Mode[16] = "IL2P"; - - sprintf(Mode, "IL2P %d", centreFreq); - - stringAdd(data, pp->frame_data, pp->frame_len + 2); // QTSM assumes a CRC - - ax25_delete(pp); - - if (retries) - { - pDET->rx_decoded = decodedFEC; - pDET->emph_decoded = decodedFEC; - pDET->errors = retries; - } - else - { - pDET->rx_decoded = decodedNormal; - pDET->emph_decoded = decodedNormal; - pDET->errors = 0; - } - - if (detect_list[snd_ch].Count > 0 && - my_indexof(&detect_list[snd_ch], data) >= 0) - { - // Already have a copy of this frame - - freeString(data); - Debugprintf("Discarding copy rcvr %d emph %d", subchan, 0); - return; - } - - string * xx = newString(); - memset(xx->Data, 0, 16); - - Add(&detect_list_c[snd_ch], xx); - Add(&detect_list[snd_ch], data); - -// if (retries) -// sprintf(Mode, "IP2P-%d", retries); - - stringAdd(xx, Mode, strlen(Mode)); - return; - -} - - - - -alevel_t demod_get_audio_level(int chan, int subchan) -{ - alevel_t alevel; - alevel.rec = 0; - alevel.mark = 0; - alevel.space = 0; - return (alevel); -} - -void ax25_hex_dump(packet_t this_p) -{} - - -/*------------------------------------------------------------------------------ - * - * Name: ax25_from_frame - * - * Purpose: Split apart an HDLC frame to components. - * - * Inputs: fbuf - Pointer to beginning of frame. - * - * flen - Length excluding the two FCS bytes. - * - * alevel - Audio level of received signal. - * Maximum range 0 - 100. - * -1 might be used when not applicable. - * - * Returns: Pointer to new packet object or NULL if error. - * - * Outputs: Use the "get" functions to retrieve information in different ways. - * - *------------------------------------------------------------------------------*/ - - -packet_t ax25_from_frame(unsigned char *fbuf, int flen, alevel_t alevel) -{ - packet_t this_p; - - - /* - * First make sure we have an acceptable length: - * - * We are not concerned with the FCS (CRC) because someone else checked it. - * - * Is is possible to have zero length for info? - * - * In the original version, assuming APRS, the answer was no. - * We always had at least 3 octets after the address part: - * control, protocol, and first byte of info part for data type. - * - * In later versions, this restriction was relaxed so other - * variations of AX.25 could be used. Now the minimum length - * is 7+7 for addresses plus 1 for control. - * - */ - - - if (flen < AX25_MIN_PACKET_LEN || flen > AX25_MAX_PACKET_LEN) - { - Debugprintf("Frame length %d not in allowable range of %d to %d.", flen, AX25_MIN_PACKET_LEN, AX25_MAX_PACKET_LEN); - return (NULL); - } - - this_p = ax25_new(); - - /* Copy the whole thing intact. */ - - memcpy(this_p->frame_data, fbuf, flen); - this_p->frame_data[flen] = 0; - this_p->frame_len = flen; - - /* Find number of addresses. */ - - this_p->num_addr = (-1); - (void)ax25_get_num_addr(this_p); - - return (this_p); -} - - - -/*------------------------------------------------------------------------------ - * - * Name: ax25_get_num_addr - * - * Purpose: Return number of addresses in current packet. - * - * Assumption: ax25_from_text or ax25_from_frame was called first. - * - * Returns: Number of addresses in the current packet. - * Should be in the range of 2 .. AX25_MAX_ADDRS. - * - * Version 0.9: Could be zero for a non AX.25 frame in KISS mode. - * - *------------------------------------------------------------------------------*/ - -int ax25_get_num_addr(packet_t this_p) -{ - //unsigned char *pf; - int a; - int addr_bytes; - - -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - /* Use cached value if already set. */ - - if (this_p->num_addr >= 0) { - return (this_p->num_addr); - } - - /* Otherwise, determine the number ofaddresses. */ - - this_p->num_addr = 0; /* Number of addresses extracted. */ - - addr_bytes = 0; - for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) { - if (this_p->frame_data[a] & SSID_LAST_MASK) { - addr_bytes = a + 1; - } - } - - if (addr_bytes % 7 == 0) { - int addrs = addr_bytes / 7; - if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) { - this_p->num_addr = addrs; - } - } - - return (this_p->num_addr); -} - - - -void ax25_get_addr_with_ssid(packet_t pp, int n, char *station) -{} - -/*------------------------------------------------------------------------------ - * - * Name: ax25_get_addr_no_ssid - * - * Purpose: Return specified address WITHOUT any SSID. - * - * Inputs: n - Index of address. Use the symbols - * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. - * - * Outputs: station - String representation of the station, WITHOUT the SSID. - * e.g. "WB2OSZ" - * Usually variables will be AX25_MAX_ADDR_LEN bytes - * but 7 would be adequate. - * - * Bugs: No bounds checking is performed. Be careful. - * - * Assumption: ax25_from_text or ax25_from_frame was called first. - * - * Returns: Character string in usual human readable format, - * - * - *------------------------------------------------------------------------------*/ - -void ax25_get_addr_no_ssid(packet_t this_p, int n, char *station) -{ - int i; - - //assert(this_p->magic1 == MAGIC); - //assert(this_p->magic2 == MAGIC); - - - if (n < 0) { - Debugprintf("Internal error detected in ax25_get_addr_no_ssid, %s, line %d.\n", __FILE__, __LINE__); - Debugprintf("Address index, %d, is less than zero.\n", n); - strcpy(station, "??????"); - return; - } - - if (n >= this_p->num_addr) { - Debugprintf("Internal error detected in ax25_get_no_with_ssid, %s, line %d.\n", __FILE__, __LINE__); - Debugprintf("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr); - strcpy(station, "??????"); - return; - } - - // At one time this would stop at the first space, on the assumption we would have only trailing spaces. - // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space. - // In that case, we would have returned a zero length string here. - // Now we return exactly what is in the address field and trim trailing spaces. - // This will provide better information for troubleshooting. - - for (i = 0; i < 6; i++) { - station[i] = (this_p->frame_data[n * 7 + i] >> 1) & 0x7f; - } - station[6] = '\0'; - - for (i = 5; i >= 0; i--) { - if (station[i] == ' ') - station[i] = '\0'; - else - break; - } - - if (strlen(station) == 0) { - Debugprintf("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n); - } - -} /* end ax25_get_addr_no_ssid */ - - -/*------------------------------------------------------------------------------ - * - * Name: ax25_get_ssid - * - * Purpose: Return SSID of specified address in current packet. - * - * Inputs: n - Index of address. Use the symbols - * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. - * - * Assumption: ax25_from_text or ax25_from_frame was called first. - * - * Returns: Substation id, as integer 0 .. 15. - * - *------------------------------------------------------------------------------*/ - -int ax25_get_ssid(packet_t this_p, int n) -{ - -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - if (n >= 0 && n < this_p->num_addr) { - return ((this_p->frame_data[n * 7 + 6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT); - } - else { - Debugprintf("Internal error: ax25_get_ssid(%d), num_addr=%d\n", n, this_p->num_addr); - return (0); - } -} - - - -static inline int ax25_get_pid_offset(packet_t this_p) -{ - return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); -} - -static int ax25_get_num_pid(packet_t this_p) -{ - int c; - int pid; - - c = this_p->frame_data[ax25_get_control_offset(this_p)]; - - if ((c & 0x01) == 0 || /* I xxxx xxx0 */ - c == 0x03 || c == 0x13) { /* UI 000x 0011 */ - - pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; - if (pid == AX25_PID_ESCAPE_CHARACTER) { - return (2); /* pid 1111 1111 means another follows. */ - } - return (1); - } - return (0); -} - - -inline int ax25_get_control_offset(packet_t this_p) -{ - return (this_p->num_addr * 7); -} - -inline int ax25_get_num_control(packet_t this_p) -{ - int c; - - c = this_p->frame_data[ax25_get_control_offset(this_p)]; - - if ((c & 0x01) == 0) { /* I xxxx xxx0 */ - return ((this_p->modulo == 128) ? 2 : 1); - } - - if ((c & 0x03) == 1) { /* S xxxx xx01 */ - return ((this_p->modulo == 128) ? 2 : 1); - } - - return (1); /* U xxxx xx11 */ -} - - - - -int ax25_get_info_offset(packet_t this_p) -{ - int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); - return (offset); -} - -int ax25_get_num_info(packet_t this_p) -{ - int len; - - /* assuming AX.25 frame. */ - - len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); - if (len < 0) { - len = 0; /* print error? */ - } - - return (len); -} - - - - - - /*------------------------------------------------------------------------------ - * - * Name: ax25_get_info - * - * Purpose: Obtain Information part of current packet. - * - * Inputs: this_p - Packet object pointer. - * - * Outputs: paddr - Starting address of information part is returned here. - * - * Assumption: ax25_from_text or ax25_from_frame was called first. - * - * Returns: Number of octets in the Information part. - * Should be in the range of AX25_MIN_INFO_LEN .. AX25_MAX_INFO_LEN. - * - *------------------------------------------------------------------------------*/ - -int ax25_get_info(packet_t this_p, unsigned char **paddr) -{ - unsigned char *info_ptr; - int info_len; - - - //assert(this_p->magic1 == MAGIC); - //assert(this_p->magic2 == MAGIC); - - if (this_p->num_addr >= 2) { - - /* AX.25 */ - - info_ptr = this_p->frame_data + ax25_get_info_offset(this_p); - info_len = ax25_get_num_info(this_p); - } - else { - - /* Not AX.25. Treat Whole packet as info. */ - - info_ptr = this_p->frame_data; - info_len = this_p->frame_len; - } - - /* Add nul character in case caller treats as printable string. */ - -// assert(info_len >= 0); - - info_ptr[info_len] = '\0'; - - *paddr = info_ptr; - return (info_len); - -} /* end ax25_get_info */ - - - - -void ax25_set_info(packet_t this_p, unsigned char *new_info_ptr, int new_info_len) -{ - unsigned char *old_info_ptr; - int old_info_len = ax25_get_info(this_p, &old_info_ptr); - this_p->frame_len -= old_info_len; - - if (new_info_len < 0) new_info_len = 0; - if (new_info_len > AX25_MAX_INFO_LEN) new_info_len = AX25_MAX_INFO_LEN; - memcpy(old_info_ptr, new_info_ptr, new_info_len); - this_p->frame_len += new_info_len; -} - -int ax25_get_pid(packet_t this_p) -{ -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - // TODO: handle 2 control byte case. - // TODO: sanity check: is it I or UI frame? - - if (this_p->frame_len == 0) return(-1); - - if (this_p->num_addr >= 2) { - return (this_p->frame_data[ax25_get_pid_offset(this_p)]); - } - return (-1); -} - - -int ax25_get_frame_len(packet_t this_p) -{ -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - -// assert(this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); - - return (this_p->frame_len); - -} /* end ax25_get_frame_len */ - - -unsigned char *ax25_get_frame_data_ptr(packet_t this_p) -{ -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - return (this_p->frame_data); - -} /* end ax25_get_frame_data_ptr */ - - -int ax25_get_modulo(packet_t this_p) -{ - return 7; -} - - -/*------------------------------------------------------------------ - * - * Function: ax25_get_control - ax25_get_c2 - * - * Purpose: Get Control field from packet. - * - * Inputs: this_p - pointer to packet object. - * - * Returns: APRS uses AX25_UI_FRAME. - * This could also be used in other situations. - * - *------------------------------------------------------------------*/ - - -int ax25_get_control(packet_t this_p) -{ -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - if (this_p->frame_len == 0) return(-1); - - if (this_p->num_addr >= 2) { - return (this_p->frame_data[ax25_get_control_offset(this_p)]); - } - return (-1); -} - - -/*------------------------------------------------------------------ -* -* Function: ax25_frame_type -* -* Purpose : Extract the type of frame. -* This is derived from the control byte(s) but -* is an enumerated type for easier handling. -* -* Inputs : this_p - pointer to packet object. -* -* Outputs : desc - Text description such as "I frame" or -*"U frame SABME". -* Supply 56 bytes to be safe. -* -* cr - Command or response ? -* -* pf - P / F - Poll / Final or -1 if not applicable -* -* nr - N(R) - receive sequence or -1 if not applicable. -* -* ns - N(S) - send sequence or -1 if not applicable. -* -* Returns: Frame type from enum ax25_frame_type_e. -* -*------------------------------------------------------------------*/ - -// TODO: need someway to ensure caller allocated enough space. -// Should pass in as parameter. - -#define DESC_SIZ 56 - - -ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns) -{ - int c; // U frames are always one control byte. - int c2 = 0; // I & S frames can have second Control byte. - -// assert(this_p->magic1 == MAGIC); -// assert(this_p->magic2 == MAGIC); - - - strcpy(desc, "????"); - *cr = cr_11; - *pf = -1; - *nr = -1; - *ns = -1; - - c = ax25_get_control(this_p); - if (c < 0) { - strcpy(desc, "Not AX.25"); - return (frame_not_AX25); - } - - /* - * TERRIBLE HACK :-( for display purposes. - * - * I and S frames can have 1 or 2 control bytes but there is - * no good way to determine this without dipping into the data - * link state machine. Can we guess? - * - * S frames have no protocol id or information so if there is one - * more byte beyond the control field, we could assume there are - * two control bytes. - * - * For I frames, the protocol id will usually be 0xf0. If we find - * that as the first byte of the information field, it is probably - * the pid and not part of the information. Ditto for segments 0x08. - * Not fool proof but good enough for troubleshooting text out. - * - * If we have a link to the peer station, this will be set properly - * before it needs to be used for other reasons. - * - * Setting one of the RR bits (find reference!) is sounding better and better. - * It's in common usage so I should lobby to get that in the official protocol spec. - */ - - // Dont support mod 128 -/* - if (this_p->modulo == 0 && (c & 3) == 1 && ax25_get_c2(this_p) != -1) { - this_p->modulo = modulo_128; - } - else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0xF0) { - this_p->modulo = modulo_128; - } - else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0x08) { // same for segments - this_p->modulo = modulo_128; - } - - - if (this_p->modulo == modulo_128) { - c2 = ax25_get_c2(this_p); - } -*/ - - int dst_c = this_p->frame_data[AX25_DESTINATION * 7 + 6] & SSID_H_MASK; - int src_c = this_p->frame_data[AX25_SOURCE * 7 + 6] & SSID_H_MASK; - - char cr_text[8]; - char pf_text[8]; - - if (dst_c) { - if (src_c) { *cr = cr_11; strcpy(cr_text, "cc=11"); strcpy(pf_text, "p/f"); } - else { *cr = cr_cmd; strcpy(cr_text, "cmd"); strcpy(pf_text, "p"); } - } - else { - if (src_c) { *cr = cr_res; strcpy(cr_text, "res"); strcpy(pf_text, "f"); } - else { *cr = cr_00; strcpy(cr_text, "cc=00"); strcpy(pf_text, "p/f"); } - } - - if ((c & 1) == 0) { - - // Information rrr p sss 0 or sssssss 0 rrrrrrr p - - if (this_p->modulo == modulo_128) { - *ns = (c >> 1) & 0x7f; - *pf = c2 & 1; - *nr = (c2 >> 1) & 0x7f; - } - else { - *ns = (c >> 1) & 7; - *pf = (c >> 4) & 1; - *nr = (c >> 5) & 7; - } - - //snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d", cr_text, *ns, *nr, pf_text, *pf); - sprintf(desc, "I %s, n(s)=%d, n(r)=%d, %s=%d, pid=0x%02x", cr_text, *ns, *nr, pf_text, *pf, ax25_get_pid(this_p)); - return (frame_type_I); - } - else if ((c & 2) == 0) { - - // Supervisory rrr p/f ss 0 1 or 0000 ss 0 1 rrrrrrr p/f - - if (this_p->modulo == modulo_128) { - *pf = c2 & 1; - *nr = (c2 >> 1) & 0x7f; - } - else { - *pf = (c >> 4) & 1; - *nr = (c >> 5) & 7; - } - - - switch ((c >> 2) & 3) { - case 0: sprintf(desc, "RR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RR); break; - case 1: sprintf(desc, "RNR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RNR); break; - case 2: sprintf(desc, "REJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_REJ); break; - case 3: sprintf(desc, "SREJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_SREJ); break; - } - } - else { - - // Unnumbered mmm p/f mm 1 1 - - *pf = (c >> 4) & 1; - - switch (c & 0xef) { - - case 0x6f: sprintf(desc, "SABME %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABME); break; - case 0x2f: sprintf(desc, "SABM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABM); break; - case 0x43: sprintf(desc, "DISC %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DISC); break; - case 0x0f: sprintf(desc, "DM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DM); break; - case 0x63: sprintf(desc, "UA %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UA); break; - case 0x87: sprintf(desc, "FRMR %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_FRMR); break; - case 0x03: sprintf(desc, "UI %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UI); break; - case 0xaf: sprintf(desc, "XID %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_XID); break; - case 0xe3: sprintf(desc, "TEST %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_TEST); break; - default: sprintf(desc, "U other???"); return (frame_type_U); break; - } - } - - // Should be unreachable but compiler doesn't realize that. - // Here only to suppress "warning: control reaches end of non-void function" - - return (frame_not_AX25); - -} /* end ax25_frame_type */ - - - -packet_t ax25_u_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len) -{ - packet_t this_p; - unsigned char *p; - int ctrl = 0; - unsigned int t = 999; // 1 = must be cmd, 0 = must be response, 2 = can be either. - int i = 0; // Is Info part allowed? - - this_p = ax25_new(); - - if (this_p == NULL) return (NULL); - - this_p->modulo = 0; - - if (!set_addrs(this_p, addrs, num_addr, cr)) { - Debugprintf("Internal error in %s: Could not set addresses for U frame.\n", __func__); - ax25_delete(this_p); - return (NULL); - } - - switch (ftype) { - // 1 = cmd only, 0 = res only, 2 = either - case frame_type_U_SABME: ctrl = 0x6f; t = 1; break; - case frame_type_U_SABM: ctrl = 0x2f; t = 1; break; - case frame_type_U_DISC: ctrl = 0x43; t = 1; break; - case frame_type_U_DM: ctrl = 0x0f; t = 0; break; - case frame_type_U_UA: ctrl = 0x63; t = 0; break; - case frame_type_U_FRMR: ctrl = 0x87; t = 0; i = 1; break; - case frame_type_U_UI: ctrl = 0x03; t = 2; i = 1; break; - case frame_type_U_XID: ctrl = 0xaf; t = 2; i = 1; break; - case frame_type_U_TEST: ctrl = 0xe3; t = 2; i = 1; break; - - default: - Debugprintf("Internal error in %s: Invalid ftype %d for U frame.\n", __func__, ftype); - ax25_delete(this_p); - return (NULL); - break; - } - if (pf) ctrl |= 0x10; - - if (t != 2) { - if (cr != t) { - Debugprintf("Internal error in %s: U frame, cr is %d but must be %d. ftype=%d\n", __func__, cr, t, ftype); - } - } - - p = this_p->frame_data + this_p->frame_len; - *p++ = ctrl; - this_p->frame_len++; - - if (ftype == frame_type_U_UI) { - - // Definitely don't want pid value of 0 (not in valid list) - // or 0xff (which means more bytes follow). - - if (pid < 0 || pid == 0 || pid == 0xff) { - Debugprintf("Internal error in %s: U frame, Invalid pid value 0x%02x.\n", __func__, pid); - pid = AX25_PID_NO_LAYER_3; - } - *p++ = pid; - this_p->frame_len++; - } - - if (i) { - if (pinfo != NULL && info_len > 0) { - if (info_len > AX25_MAX_INFO_LEN) { - - Debugprintf("Internal error in %s: U frame, Invalid information field length %d.\n", __func__, info_len); - info_len = AX25_MAX_INFO_LEN; - } - memcpy(p, pinfo, info_len); - p += info_len; - this_p->frame_len += info_len; - } - } - else { - if (pinfo != NULL && info_len > 0) { - Debugprintf("Internal error in %s: Info part not allowed for U frame type.\n", __func__); - } - } - *p = '\0'; - - //assert(p == this_p->frame_data + this_p->frame_len); - //assert(this_p->magic1 == MAGIC); - //assert(this_p->magic2 == MAGIC); - -#if PAD2TEST - ax25_frame_type_t check_ftype; - cmdres_t check_cr; - char check_desc[80]; - int check_pf; - int check_nr; - int check_ns; - - check_ftype = ax25_frame_type(this_p, &check_cr, check_desc, &check_pf, &check_nr, &check_ns); - - text_color_set(DW_COLOR_DEBUG); - Debugprintf("check: ftype=%d, desc=\"%s\", pf=%d\n", check_ftype, check_desc, check_pf); - - assert(check_cr == cr); - assert(check_ftype == ftype); - assert(check_pf == pf); - assert(check_nr == -1); - assert(check_ns == -1); - -#endif - - return (this_p); - -} /* end ax25_u_frame */ - - - - - - -static const char *position_name[1 + AX25_MAX_ADDRS] = { - "", "Destination ", "Source ", - "Digi1 ", "Digi2 ", "Digi3 ", "Digi4 ", - "Digi5 ", "Digi6 ", "Digi7 ", "Digi8 " }; - -int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard) -{ - char *p; - char sstr[8]; /* Should be 1 or 2 digits for SSID. */ - int i, j, k; - int maxlen; - - *out_addr = '\0'; - *out_ssid = 0; - *out_heard = 0; - - // Debugprintf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict); - - if (position < -1) position = -1; - if (position > AX25_REPEATER_8) position = AX25_REPEATER_8; - position++; /* Adjust for position_name above. */ - - if (strlen(in_addr) == 0) { - Debugprintf("%sAddress \"%s\" is empty.\n", position_name[position], in_addr); - return 0; - } - - if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) { - - Debugprintf("%sAddress \"%s\" is a \"q-construct\" used for communicating with\n", position_name[position], in_addr); - Debugprintf("APRS Internet Servers. It should never appear when going over the radio.\n"); - } - - // Debugprintf ("ax25_parse_addr in: %s\n", in_addr); - - maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN - 1); - p = in_addr; - i = 0; - for (p = in_addr; *p != '\0' && *p != '-' && *p != '*'; p++) { - if (i >= maxlen) { - Debugprintf("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen); - return 0; - } - if (!isalnum(*p)) { - Debugprintf("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p - in_addr) + 1); - return 0; - } - - out_addr[i++] = *p; - out_addr[i] = '\0'; - -#if DECAMAIN // Hack when running in decode_aprs utility. - // Exempt the "qA..." case because it was already mentioned. - - if (strict && islower(*p) && strncmp(in_addr, "qA", 2) != 0) { - text_color_set(DW_COLOR_ERROR); - Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); - } -#else - if (strict && islower(*p)) { - Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); - return 0; - } -#endif - } - - j = 0; - sstr[j] = '\0'; - if (*p == '-') { - for (p++; isalnum(*p); p++) { - if (j >= 2) { - Debugprintf("%sSSID is too long. SSID part of \"%s\" has more than 2 characters.\n", position_name[position], in_addr); - return 0; - } - sstr[j++] = *p; - sstr[j] = '\0'; - if (strict && !isdigit(*p)) { - Debugprintf("%sSSID must be digits. \"%s\" has letters in SSID.\n", position_name[position], in_addr); - return 0; - } - } - k = atoi(sstr); - if (k < 0 || k > 15) { - Debugprintf("%sSSID out of range. SSID of \"%s\" not in range of 0 to 15.\n", position_name[position], in_addr); - return 0; - } - *out_ssid = k; - } - - if (*p == '*') { - *out_heard = 1; - p++; - if (strict == 2) { - Debugprintf("\"*\" is not allowed at end of address \"%s\" here.\n", in_addr); - return 0; - } - } - - if (*p != '\0') { - Debugprintf("Invalid character \"%c\" found in %saddress \"%s\".\n", *p, position_name[position], in_addr); - return 0; - } - - // Debugprintf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard); - - return (1); - -} /* end ax25_parse_addr */ - - - -int set_addrs(packet_t pp, char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr) -{ - int n; - - //assert(pp->frame_len == 0); - //assert(cr == cr_cmd || cr == cr_res); - - if (num_addr < AX25_MIN_ADDRS || num_addr > AX25_MAX_ADDRS) { - Debugprintf("INTERNAL ERROR: %s %s %d, num_addr = %d\n", __FILE__, __func__, __LINE__, num_addr); - return (0); - } - - for (n = 0; n < num_addr; n++) { - - unsigned char *pa = pp->frame_data + n * 7; - int ok; - int strict = 1; - char oaddr[AX25_MAX_ADDR_LEN]; - int ssid; - int heard; - int j; - - ok = ax25_parse_addr(n, addrs[n], strict, oaddr, &ssid, &heard); - - if (!ok) return (0); - - // Fill in address. - - memset(pa, ' ' << 1, 6); - for (j = 0; oaddr[j]; j++) { - pa[j] = oaddr[j] << 1; - } - pa += 6; - - // Fill in SSID. - - *pa = 0x60 | ((ssid & 0xf) << 1); - - // Command / response flag. - - switch (n) { - case AX25_DESTINATION: - if (cr == cr_cmd) *pa |= 0x80; - break; - case AX25_SOURCE: - if (cr == cr_res) *pa |= 0x80; - break; - default: - break; - } - - // Is this the end of address field? - - if (n == num_addr - 1) { - *pa |= 1; - } - - pp->frame_len += 7; - } - - pp->num_addr = num_addr; - return (1); - -} /* end set_addrs */ - - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_init.c -// -/////////////////////////////////////////////////////////////////////////////// - - -// Init must be called at start of application. - -extern void il2p_init(int debug); - -extern struct rs *il2p_find_rs(int nparity); // Internal later? - -extern void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out); - -extern int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out); - -extern int il2p_get_debug(void); -extern void il2p_set_debug(int debug); - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_rec.c -// -/////////////////////////////////////////////////////////////////////////////// - -// Receives a bit stream from demodulator. - -extern void il2p_rec_bit(int chan, int subchan, int slice, int dbit); - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_send.c -// -/////////////////////////////////////////////////////////////////////////////// - - -// Send bit stream to modulator. - -string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_codec.c -// -/////////////////////////////////////////////////////////////////////////////// - - -extern int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout); - -packet_t il2p_decode_frame(unsigned char *irec); - -packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected); - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_header.c -// -/////////////////////////////////////////////////////////////////////////////// - - -extern int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr); - -extern packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed); - - -extern int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr); - -extern int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_scramble.c -// -/////////////////////////////////////////////////////////////////////////////// - -extern void il2p_scramble_block(unsigned char *in, unsigned char *out, int len); - -extern void il2p_descramble_block(unsigned char *in, unsigned char *out, int len); - - -/////////////////////////////////////////////////////////////////////////////// -// -// il2p_payload.c -// -/////////////////////////////////////////////////////////////////////////////// - - -typedef struct { - int payload_byte_count; // Total size, 0 thru 1023 - int payload_block_count; - int small_block_size; - int large_block_size; - int large_block_count; - int small_block_count; - int parity_symbols_per_block; // 2, 4, 6, 8, 16 -} il2p_payload_properties_t; - -extern int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec); - -extern int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc); - -extern int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected); - -extern int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec); - -#endif - - - -// Interesting related stuff: -// https://www.kernel.org/doc/html/v4.15/core-api/librs.html -// https://berthub.eu/articles/posts/reed-solomon-for-programmers/ - - -#define MAX_NROOTS 16 - -#define NTAB 5 - -static struct { - int symsize; // Symbol size, bits (1-8). Always 8 for this application. - int genpoly; // Field generator polynomial coefficients. - int fcs; // First root of RS code generator polynomial, index form. - // FX.25 uses 1 but IL2P uses 0. - int prim; // Primitive element to generate polynomial roots. - int nroots; // RS code generator polynomial degree (number of roots). - // Same as number of check bytes added. - struct rs *rs; // Pointer to RS codec control block. Filled in at init time. -} Tab[NTAB] = { - {8, 0x11d, 0, 1, 2, NULL }, // 2 parity - {8, 0x11d, 0, 1, 4, NULL }, // 4 parity - {8, 0x11d, 0, 1, 6, NULL }, // 6 parity - {8, 0x11d, 0, 1, 8, NULL }, // 8 parity - {8, 0x11d, 0, 1, 16, NULL }, // 16 parity -}; - - - -static int g_il2p_debug = 0; - - -/*------------------------------------------------------------- - * - * Name: il2p_init - * - * Purpose: This must be called at application start up time. - * It sets up tables for the Reed-Solomon functions. - * - * Inputs: debug - Enable debug output. - * - *--------------------------------------------------------------*/ - -void il2p_init(int il2p_debug) -{ - g_il2p_debug = il2p_debug; - - for (int i = 0; i < NTAB; i++) { - //assert(Tab[i].nroots <= MAX_NROOTS); - Tab[i].rs = INIT_RS(Tab[i].symsize, Tab[i].genpoly, Tab[i].fcs, Tab[i].prim, Tab[i].nroots); - if (Tab[i].rs == NULL) { - Debugprintf("IL2P internal error: init_rs_char failed!\n"); - exit(0); - } - } - -} // end il2p_init - - -int il2p_get_debug(void) -{ - return (g_il2p_debug); -} -void il2p_set_debug(int debug) -{ - g_il2p_debug = debug; -} - - -// Find RS codec control block for specified number of parity symbols. - -struct rs *il2p_find_rs(int nparity) -{ - for (int n = 0; n < NTAB; n++) { - if (Tab[n].nroots == nparity) { - return (Tab[n].rs); - } - } - Debugprintf("IL2P INTERNAL ERROR: il2p_find_rs: control block not found for nparity = %d.\n", nparity); - return (Tab[0].rs); -} - - -/*------------------------------------------------------------- - * - * Name: void il2p_encode_rs - * - * Purpose: Add parity symbols to a block of data. - * - * Inputs: tx_data Header or other data to transmit. - * data_size Number of data bytes in above. - * num_parity Number of parity symbols to add. - * Maximum of IL2P_MAX_PARITY_SYMBOLS. - * - * Outputs: parity_out Specified number of parity symbols - * - * Restriction: data_size + num_parity <= 255 which is the RS block size. - * The caller must ensure this. - * - *--------------------------------------------------------------*/ - -void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out) -{ - //assert(data_size >= 1); - //assert(num_parity == 2 || num_parity == 4 || num_parity == 6 || num_parity == 8 || num_parity == 16); - //assert(data_size + num_parity <= 255); - - unsigned char rs_block[FX25_BLOCK_SIZE]; - memset(rs_block, 0, sizeof(rs_block)); - memcpy(rs_block + sizeof(rs_block) - data_size - num_parity, tx_data, data_size); - ENCODE_RS(il2p_find_rs(num_parity), rs_block, parity_out); -} - -/*------------------------------------------------------------- - * - * Name: void il2p_decode_rs - * - * Purpose: Check and attempt to fix block with FEC. - * - * Inputs: rec_block Received block composed of data and parity. - * Total size is sum of following two parameters. - * data_size Number of data bytes in above. - * num_parity Number of parity symbols (bytes) in above. - * - * Outputs: out Original with possible corrections applied. - * data_size bytes. - * - * Returns: -1 for unrecoverable. - * >= 0 for success. Number of symbols corrected. - * - *--------------------------------------------------------------*/ - -int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out) -{ - - // Use zero padding in front if data size is too small. - - int n = data_size + num_parity; // total size in. - - unsigned char rs_block[FX25_BLOCK_SIZE]; - - // We could probably do this more efficiently by skipping the - // processing of the bytes known to be zero. Good enough for now. - - memset(rs_block, 0, sizeof(rs_block) - n); - memcpy(rs_block + sizeof(rs_block) - n, rec_block, n); - - if (il2p_get_debug() >= 3) { - Debugprintf("============================== il2p_decode_rs ==============================\n"); - Debugprintf("%d filler zeros, %d data, %d parity\n", (int)(sizeof(rs_block) - n), data_size, num_parity); - fx_hex_dump(rs_block, sizeof(rs_block)); - } - - int derrlocs[FX25_MAX_CHECK]; // Half would probably be OK. - - int derrors = DECODE_RS(il2p_find_rs(num_parity), rs_block, derrlocs, 0); - memcpy(out, rs_block + sizeof(rs_block) - n, data_size); - - if (il2p_get_debug() >= 3) { - if (derrors == 0) { - Debugprintf("No errors reported for RS block.\n"); - } - else if (derrors > 0) { - Debugprintf("%d errors fixed in positions:\n", derrors); - for (int j = 0; j < derrors; j++) { - Debugprintf(" %3d (0x%02x)\n", derrlocs[j], derrlocs[j]); - } - fx_hex_dump(rs_block, sizeof(rs_block)); - } - } - - // It is possible to have a situation where too many errors are - // present but the algorithm could get a good code block by "fixing" - // one of the padding bytes that should be 0. - - for (int i = 0; i < derrors; i++) { - if (derrlocs[i] < sizeof(rs_block) - n) { - if (il2p_get_debug() >= 3) { - Debugprintf("RS DECODE ERROR! Padding position %d should be 0 but it was set to %02x.\n", derrlocs[i], rs_block[derrlocs[i]]); - } - derrors = -1; - break; - } - } - - if (il2p_get_debug() >= 3) { - Debugprintf("============================== il2p_decode_rs returns %d ==============================\n", derrors); - } - return (derrors); -} - -// end il2p_init.c - - - - - - - - - - - - - -void ENCODE_RS(struct rs * rs, DTYPE * data, DTYPE * bb) -{ - - int i, j; - DTYPE feedback; - - memset(bb, 0, NROOTS * sizeof(DTYPE)); // clear out the FEC data area - - for (i = 0; i < NN - NROOTS; i++) { - feedback = INDEX_OF[data[i] ^ bb[0]]; - if (feedback != A0) { /* feedback term is non-zero */ - for (j = 1; j < NROOTS; j++) - bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])]; - } - /* Shift */ - memmove(&bb[0], &bb[1], sizeof(DTYPE)*(NROOTS - 1)); - if (feedback != A0) - bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; - else - bb[NROOTS - 1] = 0; - } -} - - - - -int DECODE_RS(struct rs * rs, DTYPE * data, int *eras_pos, int no_eras) { - - int deg_lambda, el, deg_omega; - int i, j, r, k; - DTYPE u, q, tmp, num1, num2, den, discr_r; - // DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly and syndrome poly */ - // DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; - // DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; - DTYPE lambda[FX25_MAX_CHECK + 1], s[FX25_MAX_CHECK]; /* Err+Eras Locator poly and syndrome poly */ - DTYPE b[FX25_MAX_CHECK + 1], t[FX25_MAX_CHECK + 1], omega[FX25_MAX_CHECK + 1]; - DTYPE root[FX25_MAX_CHECK], reg[FX25_MAX_CHECK + 1], loc[FX25_MAX_CHECK]; - int syn_error, count; - - /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ - for (i = 0; i < NROOTS; i++) - s[i] = data[0]; - - for (j = 1; j < NN; j++) { - for (i = 0; i < NROOTS; i++) { - if (s[i] == 0) { - s[i] = data[j]; - } - else { - s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i)*PRIM)]; - } - } - } - - /* Convert syndromes to index form, checking for nonzero condition */ - syn_error = 0; - for (i = 0; i < NROOTS; i++) { - syn_error |= s[i]; - s[i] = INDEX_OF[s[i]]; - } - - // fprintf(stderr,"syn_error = %4x\n",syn_error); - if (!syn_error) { - /* if syndrome is zero, data[] is a codeword and there are no - * errors to correct. So return data[] unmodified - */ - count = 0; - goto finish; - } - memset(&lambda[1], 0, NROOTS * sizeof(lambda[0])); - lambda[0] = 1; - - if (no_eras > 0) { - /* Init lambda to be the erasure locator polynomial */ - lambda[1] = ALPHA_TO[MODNN(PRIM*(NN - 1 - eras_pos[0]))]; - for (i = 1; i < no_eras; i++) { - u = MODNN(PRIM*(NN - 1 - eras_pos[i])); - for (j = i + 1; j > 0; j--) { - tmp = INDEX_OF[lambda[j - 1]]; - if (tmp != A0) - lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; - } - } - -#if DEBUG >= 1 - /* Test code that verifies the erasure locator polynomial just constructed - Needed only for decoder debugging. */ - - /* find roots of the erasure location polynomial */ - for (i = 1; i <= no_eras; i++) - reg[i] = INDEX_OF[lambda[i]]; - - count = 0; - for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { - q = 1; - for (j = 1; j <= no_eras; j++) - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - if (q != 0) - continue; - /* store root and error location number indices */ - root[count] = i; - loc[count] = k; - count++; - } - if (count != no_eras) { - fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n", count, no_eras); - count = -1; - goto finish; - } -#if DEBUG >= 2 - fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n"); - for (i = 0; i < count; i++) - fprintf(stderr, "%d ", loc[i]); - fprintf(stderr, "\n"); -#endif -#endif - } - for (i = 0; i < NROOTS + 1; i++) - b[i] = INDEX_OF[lambda[i]]; - - /* - * Begin Berlekamp-Massey algorithm to determine error+erasure - * locator polynomial - */ - r = no_eras; - el = no_eras; - while (++r <= NROOTS) { /* r is the step number */ - /* Compute discrepancy at the r-th step in poly-form */ - discr_r = 0; - for (i = 0; i < r; i++) { - if ((lambda[i] != 0) && (s[r - i - 1] != A0)) { - discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])]; - } - } - discr_r = INDEX_OF[discr_r]; /* Index form */ - if (discr_r == A0) { - /* 2 lines below: B(x) <-- x*B(x) */ - memmove(&b[1], b, NROOTS * sizeof(b[0])); - b[0] = A0; - } - else { - /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ - t[0] = lambda[0]; - for (i = 0; i < NROOTS; i++) { - if (b[i] != A0) - t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])]; - else - t[i + 1] = lambda[i + 1]; - } - if (2 * el <= r + no_eras - 1) { - el = r + no_eras - el; - /* - * 2 lines below: B(x) <-- inv(discr_r) * - * lambda(x) - */ - for (i = 0; i <= NROOTS; i++) - b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN); - } - else { - /* 2 lines below: B(x) <-- x*B(x) */ - memmove(&b[1], b, NROOTS * sizeof(b[0])); - b[0] = A0; - } - memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0])); - } - } - - /* Convert lambda to index form and compute deg(lambda(x)) */ - deg_lambda = 0; - for (i = 0; i < NROOTS + 1; i++) { - lambda[i] = INDEX_OF[lambda[i]]; - if (lambda[i] != A0) - deg_lambda = i; - } - /* Find roots of the error+erasure locator polynomial by Chien search */ - memcpy(®[1], &lambda[1], NROOTS * sizeof(reg[0])); - count = 0; /* Number of roots of lambda(x) */ - for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { - q = 1; /* lambda[0] is always 0 */ - for (j = deg_lambda; j > 0; j--) { - if (reg[j] != A0) { - reg[j] = MODNN(reg[j] + j); - q ^= ALPHA_TO[reg[j]]; - } - } - if (q != 0) - continue; /* Not a root */ - /* store root (index-form) and error location number */ -#if DEBUG>=2 - fprintf(stderr, "count %d root %d loc %d\n", count, i, k); -#endif - root[count] = i; - loc[count] = k; - /* If we've already found max possible roots, - * abort the search to save time - */ - if (++count == deg_lambda) - break; - } - if (deg_lambda != count) { - /* - * deg(lambda) unequal to number of roots => uncorrectable - * error detected - */ - count = -1; - goto finish; - } - /* - * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo - * x**NROOTS). in index form. Also find deg(omega). - */ - deg_omega = 0; - for (i = 0; i < NROOTS; i++) { - tmp = 0; - j = (deg_lambda < i) ? deg_lambda : i; - for (; j >= 0; j--) { - if ((s[i - j] != A0) && (lambda[j] != A0)) - tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; - } - if (tmp != 0) - deg_omega = i; - omega[i] = INDEX_OF[tmp]; - } - omega[NROOTS] = A0; - - /* - * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = - * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form - */ - for (j = count - 1; j >= 0; j--) { - num1 = 0; - for (i = deg_omega; i >= 0; i--) { - if (omega[i] != A0) - num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; - } - num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; - den = 0; - - /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ - for (i = min(deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) { - if (lambda[i + 1] != A0) - den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])]; - } - if (den == 0) { -#if DEBUG >= 1 - fprintf(stderr, "\n ERROR: denominator = 0\n"); -#endif - count = -1; - goto finish; - } - /* Apply error to data */ - if (num1 != 0) { - data[loc[j]] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; - } - } -finish: - if (eras_pos != NULL) { - for (i = 0; i < count; i++) - eras_pos[i] = loc[i]; - } - return count; -} - - - - -struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, unsigned fcr, unsigned prim, - unsigned int nroots) { - struct rs *rs; - int i, j, sr, root, iprim; - - if (symsize > 8 * sizeof(DTYPE)) - return NULL; /* Need version with ints rather than chars */ - - if (fcr >= (1 << symsize)) - return NULL; - if (prim == 0 || prim >= (1 << symsize)) - return NULL; - if (nroots >= (1 << symsize)) - return NULL; /* Can't have more roots than symbol values! */ - - rs = (struct rs *)calloc(1, sizeof(struct rs)); - if (rs == NULL) { - Debugprintf("FATAL ERROR: Out of memory.\n"); - exit(0); - } - rs->mm = symsize; - rs->nn = (1 << symsize) - 1; - - rs->alpha_to = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); - if (rs->alpha_to == NULL) { - Debugprintf("FATAL ERROR: Out of memory.\n"); - exit(0); - } - rs->index_of = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); - if (rs->index_of == NULL) { - Debugprintf("FATAL ERROR: Out of memory.\n"); - exit(0); - } - - /* Generate Galois field lookup tables */ - rs->index_of[0] = A0; /* log(zero) = -inf */ - rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ - sr = 1; - for (i = 0; i < rs->nn; i++) { - rs->index_of[sr] = i; - rs->alpha_to[i] = sr; - sr <<= 1; - if (sr & (1 << symsize)) - sr ^= gfpoly; - sr &= rs->nn; - } - if (sr != 1) { - /* field generator polynomial is not primitive! */ - free(rs->alpha_to); - free(rs->index_of); - free(rs); - return NULL; - } - - /* Form RS code generator polynomial from its roots */ - rs->genpoly = (DTYPE *)calloc((nroots + 1), sizeof(DTYPE)); - if (rs->genpoly == NULL) { - Debugprintf("FATAL ERROR: Out of memory.\n"); - exit(0); - } - rs->fcr = fcr; - rs->prim = prim; - rs->nroots = nroots; - - /* Find prim-th root of 1, used in decoding */ - for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn) - ; - rs->iprim = iprim / prim; - - rs->genpoly[0] = 1; - for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) { - rs->genpoly[i + 1] = 1; - - /* Multiply rs->genpoly[] by @**(root + x) */ - for (j = i; j > 0; j--) { - if (rs->genpoly[j] != 0) - rs->genpoly[j] = rs->genpoly[j - 1] ^ rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; - else - rs->genpoly[j] = rs->genpoly[j - 1]; - } - /* rs->genpoly[0] can never be zero */ - rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; - } - /* convert rs->genpoly[] to index form for quicker encoding */ - for (i = 0; i <= nroots; i++) { - rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; - } - - // diagnostic prints -#if 0 - printf("Alpha To:\n\r"); - for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) - printf("0x%2x,", rs->alpha_to[i]); - printf("\n\r"); - - printf("Index Of:\n\r"); - for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) - printf("0x%2x,", rs->index_of[i]); - printf("\n\r"); - - printf("GenPoly:\n\r"); - for (i = 0; i <= nroots; i++) - printf("0x%2x,", rs->genpoly[i]); - printf("\n\r"); -#endif - return rs; -} - - -// TEMPORARY!!! -// FIXME: We already have multiple copies of this. -// Consolidate them into one somewhere. - -void fx_hex_dump(unsigned char *p, int len) -{ - int n, i, offset; - - offset = 0; - while (len > 0) { - n = len < 16 ? len : 16; - Debugprintf(" %03x: ", offset); - for (i = 0; i < n; i++) { - Debugprintf(" %02x", p[i]); - } - for (i = n; i < 16; i++) { - Debugprintf(" "); - } - Debugprintf(" "); - for (i = 0; i < n; i++) { - Debugprintf("%c", isprint(p[i]) ? p[i] : '.'); - } - Debugprintf("\n"); - p += 16; - offset += 16; - len -= 16; - } -} - - -/*------------------------------------------------------------- - * - * File: il2p_codec.c - * - * Purpose: Convert IL2P encoded format from and to direwolf internal packet format. - * - *--------------------------------------------------------------*/ - - - /*------------------------------------------------------------- - * - * Name: il2p_encode_frame - * - * Purpose: Convert AX.25 frame to IL2P encoding. - * - * Inputs: chan - Audio channel number, 0 = first. - * - * pp - Packet object pointer. - * - * max_fec - 1 to send maximum FEC size rather than automatic. - * - * Outputs: iout - Encoded result, excluding the 3 byte sync word. - * Caller should provide IL2P_MAX_PACKET_SIZE bytes. - * - * Returns: Number of bytes for transmission. - * -1 is returned for failure. - * - * Description: Encode into IL2P format. - * - * Errors: If something goes wrong, return -1. - * - * Most likely reason is that the frame is too large. - * IL2P has a max payload size of 1023 bytes. - * For a type 1 header, this is the maximum AX.25 Information part size. - * For a type 0 header, this is the entire AX.25 frame. - * - *--------------------------------------------------------------*/ - -int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout) -{ - - // Can a type 1 header be used? - - unsigned char hdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; - int e; - int out_len = 0; - - e = il2p_type_1_header(pp, max_fec, hdr); - if (e >= 0) { - il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); - il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); - out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; - - if (e == 0) { - // Success. No info part. - return (out_len); - } - - // Payload is AX.25 info part. - unsigned char *pinfo; - int info_len; - info_len = ax25_get_info(pp, &pinfo); - - int k = il2p_encode_payload(pinfo, info_len, max_fec, iout + out_len); - if (k > 0) { - out_len += k; - // Success. Info part was <= 1023 bytes. - return (out_len); - } - - // Something went wrong with the payload encoding. - return (-1); - } - else if (e == -1) { - - // Could not use type 1 header for some reason. - // e.g. More than 2 addresses, extended (mod 128) sequence numbers, etc. - - e = il2p_type_0_header(pp, max_fec, hdr); - if (e > 0) { - - il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); - il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); - out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; - - // Payload is entire AX.25 frame. - - unsigned char *frame_data_ptr = ax25_get_frame_data_ptr(pp); - int frame_len = ax25_get_frame_len(pp); - int k = il2p_encode_payload(frame_data_ptr, frame_len, max_fec, iout + out_len); - if (k > 0) { - out_len += k; - // Success. Entire AX.25 frame <= 1023 bytes. - return (out_len); - } - // Something went wrong with the payload encoding. - return (-1); - } - else if (e == 0) { - // Impossible condition. Type 0 header must have payload. - return (-1); - } - else { - // AX.25 frame is too large. - return (-1); - } - } - - // AX.25 Information part is too large. - return (-1); -} - - - -/*------------------------------------------------------------- - * - * Name: il2p_decode_frame - * - * Purpose: Convert IL2P encoding to AX.25 frame. - * This is only used during testing, with a whole encoded frame. - * During reception, the header would have FEC and descrambling - * applied first so we would know how much to collect for the payload. - * - * Inputs: irec - Received IL2P frame excluding the 3 byte sync word. - * - * Future Out: Number of symbols corrected. - * - * Returns: Packet pointer or NULL for error. - * - *--------------------------------------------------------------*/ - -packet_t il2p_decode_frame(unsigned char *irec) -{ - unsigned char uhdr[IL2P_HEADER_SIZE]; // After FEC and descrambling. - int e = il2p_clarify_header(irec, uhdr); - - // TODO?: for symmetry we might want to clarify the payload before combining. - - return (il2p_decode_header_payload(uhdr, irec + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY, &e)); -} - - -/*------------------------------------------------------------- - * - * Name: il2p_decode_header_payload - * - * Purpose: Convert IL2P encoding to AX.25 frame - * - * Inputs: uhdr - Received header after FEC and descrambling. - * epayload - Encoded payload. - * - * In/Out: symbols_corrected - Symbols (bytes) corrected in the header. - * Should be 0 or 1 because it has 2 parity symbols. - * Here we add number of corrections for the payload. - * - * Returns: Packet pointer or NULL for error. - * - *--------------------------------------------------------------*/ - -packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected) -{ - int hdr_type; - int max_fec; - int payload_len = il2p_get_header_attributes(uhdr, &hdr_type, &max_fec); - - packet_t pp = NULL; - - if (hdr_type == 1) { - - // Header type 1. Any payload is the AX.25 Information part. - - pp = il2p_decode_header_type_1(uhdr, *symbols_corrected); - if (pp == NULL) { - // Failed for some reason. - return (NULL); - } - - if (payload_len > 0) { - // This is the AX.25 Information part. - - unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; - int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); - - // It would be possible to have a good header but too many errors in the payload. - - if (e <= 0) { - ax25_delete(pp); - pp = NULL; - return (pp); - } - - if (e != payload_len) { - Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, max_fec=%d, payload_len=%d, e=%d.\n", __func__, hdr_type, max_fec, payload_len, e); - } - - ax25_set_info(pp, extracted, payload_len); - } - return (pp); - } - else { - - // Header type 0. The payload is the entire AX.25 frame. - - unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; - int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); - - if (e <= 0) { // Payload was not received correctly. - return (NULL); - } - - if (e != payload_len) { - Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, e=%d, payload_len=%d\n", __func__, hdr_type, e, payload_len); - return (NULL); - } - - alevel_t alevel; - memset(&alevel, 0, sizeof(alevel)); - //alevel = demod_get_audio_level (chan, subchan); // What TODO? We don't know channel here. - // I think alevel gets filled in somewhere later making - // this redundant. - - pp = ax25_from_frame(extracted, payload_len, alevel); - return (pp); - } - -} // end il2p_decode_header_payload - -// end il2p_codec.c - - - -/*-------------------------------------------------------------------------------- - * - * File: il2p_header.c - * - * Purpose: Functions to deal with the IL2P header. - * - * Reference: http://tarpn.net/t/il2p/il2p-specification0-4.pdf - * - *--------------------------------------------------------------------------------*/ - - - - // Convert ASCII to/from DEC SIXBIT as defined here: - // https://en.wikipedia.org/wiki/Six-bit_character_code#DEC_six-bit_code - -static inline int ascii_to_sixbit(int a) -{ - if (a >= ' ' && a <= '_') return (a - ' '); - return (31); // '?' for any invalid. -} - -static inline int sixbit_to_ascii(int s) -{ - return (s + ' '); -} - -// Functions for setting the various header fields. -// It is assumed that it was zeroed first so only the '1' bits are set. - -static void set_field(unsigned char *hdr, int bit_num, int lsb_index, int width, int value) -{ - while (width > 0 && value != 0) { - //assert(lsb_index >= 0 && lsb_index <= 11); - if (value & 1) { - hdr[lsb_index] |= 1 << bit_num; - } - value >>= 1; - lsb_index--; - width--; - } - //assert(value == 0); -} - -#define SET_UI(hdr,val) set_field(hdr, 6, 0, 1, val) - -#define SET_PID(hdr,val) set_field(hdr, 6, 4, 4, val) - -#define SET_CONTROL(hdr,val) set_field(hdr, 6, 11, 7, val) - - -#define SET_FEC_LEVEL(hdr,val) set_field(hdr, 7, 0, 1, val) - -#define SET_HDR_TYPE(hdr,val) set_field(hdr, 7, 1, 1, val) - -#define SET_PAYLOAD_BYTE_COUNT(hdr,val) set_field(hdr, 7, 11, 10, val) - - -// Extracting the fields. - -static int get_field(unsigned char *hdr, int bit_num, int lsb_index, int width) -{ - int result = 0; - lsb_index -= width - 1; - while (width > 0) { - result <<= 1; - //assert(lsb_index >= 0 && lsb_index <= 11); - if (hdr[lsb_index] & (1 << bit_num)) { - result |= 1; - } - lsb_index++; - width--; - } - return (result); -} - -#define GET_UI(hdr) get_field(hdr, 6, 0, 1) - -#define GET_PID(hdr) get_field(hdr, 6, 4, 4) - -#define GET_CONTROL(hdr) get_field(hdr, 6, 11, 7) - - -#define GET_FEC_LEVEL(hdr) get_field(hdr, 7, 0, 1) - -#define GET_HDR_TYPE(hdr) get_field(hdr, 7, 1, 1) - -#define GET_PAYLOAD_BYTE_COUNT(hdr) get_field(hdr, 7, 11, 10) - - - -// AX.25 'I' and 'UI' frames have a protocol ID which determines how the -// information part should be interpreted. -// Here we squeeze the most common cases down to 4 bits. -// Return -1 if translation is not possible. Fall back to type 0 header in this case. - -static int encode_pid(packet_t pp) -{ - int pid = ax25_get_pid(pp); - - if ((pid & 0x30) == 0x20) return (0x2); // AX.25 Layer 3 - if ((pid & 0x30) == 0x10) return (0x2); // AX.25 Layer 3 - if (pid == 0x01) return (0x3); // ISO 8208 / CCIT X.25 PLP - if (pid == 0x06) return (0x4); // Compressed TCP/IP - if (pid == 0x07) return (0x5); // Uncompressed TCP/IP - if (pid == 0x08) return (0x6); // Segmentation fragmen - if (pid == 0xcc) return (0xb); // ARPA Internet Protocol - if (pid == 0xcd) return (0xc); // ARPA Address Resolution - if (pid == 0xce) return (0xd); // FlexNet - if (pid == 0xcf) return (0xe); // TheNET - if (pid == 0xf0) return (0xf); // No L3 - return (-1); -} - -// Convert IL2P 4 bit PID to AX.25 8 bit PID. - - -static int decode_pid(int pid) -{ - static const unsigned char axpid[16] = { - 0xf0, // Should not happen. 0 is for 'S' frames. - 0xf0, // Should not happen. 1 is for 'U' frames (but not UI). - 0x20, // AX.25 Layer 3 - 0x01, // ISO 8208 / CCIT X.25 PLP - 0x06, // Compressed TCP/IP - 0x07, // Uncompressed TCP/IP - 0x08, // Segmentation fragment - 0xf0, // Future - 0xf0, // Future - 0xf0, // Future - 0xf0, // Future - 0xcc, // ARPA Internet Protocol - 0xcd, // ARPA Address Resolution - 0xce, // FlexNet - 0xcf, // TheNET - 0xf0 }; // No L3 - - //assert(pid >= 0 && pid <= 15); - return (axpid[pid]); -} - - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_type_1_header - * - * Purpose: Attempt to create type 1 header from packet object. - * - * Inputs: pp - Packet object. - * - * max_fec - 1 to use maximum FEC symbols , 0 for automatic. - * - * Outputs: hdr - IL2P header with no scrambling or parity symbols. - * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. - * - * Returns: Number of bytes for information part or -1 for failure. - * In case of failure, fall back to type 0 transparent encapsulation. - * - * Description: Type 1 Headers do not support AX.25 repeater callsign addressing, - * Modulo-128 extended mode window sequence numbers, nor any callsign - * characters that cannot translate to DEC SIXBIT. - * If these cases are encountered during IL2P packet encoding, - * the encoder switches to Type 0 Transparent Encapsulation. - * SABME can't be handled by type 1. - * - *--------------------------------------------------------------------------------*/ - -int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr) -{ - memset(hdr, 0, IL2P_HEADER_SIZE); - - if (ax25_get_num_addr(pp) != 2) { - // Only two addresses are allowed for type 1 header. - return (-1); - } - - // Check does not apply for 'U' frames but put in one place rather than two. - - if (ax25_get_modulo(pp) == 128) return(-1); - - // Destination and source addresses go into low bits 0-5 for bytes 0-11. - - char dst_addr[AX25_MAX_ADDR_LEN]; - char src_addr[AX25_MAX_ADDR_LEN]; - - ax25_get_addr_no_ssid(pp, AX25_DESTINATION, dst_addr); - int dst_ssid = ax25_get_ssid(pp, AX25_DESTINATION); - - ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr); - int src_ssid = ax25_get_ssid(pp, AX25_SOURCE); - - unsigned char *a = (unsigned char *)dst_addr; - for (int i = 0; *a != '\0'; i++, a++) { - if (*a < ' ' || *a > '_') { - // Shouldn't happen but follow the rule. - return (-1); - } - hdr[i] = ascii_to_sixbit(*a); - } - - a = (unsigned char *)src_addr; - for (int i = 6; *a != '\0'; i++, a++) { - if (*a < ' ' || *a > '_') { - // Shouldn't happen but follow the rule. - return (-1); - } - hdr[i] = ascii_to_sixbit(*a); - } - - // Byte 12 has DEST SSID in upper nybble and SRC SSID in lower nybble and - hdr[12] = (dst_ssid << 4) | src_ssid; - - ax25_frame_type_t frame_type; - cmdres_t cr; // command or response. - char description[64]; - int pf; // Poll/Final. - int nr, ns; // Sequence numbers. - - frame_type = ax25_frame_type(pp, &cr, description, &pf, &nr, &ns); - - //Debugprintf ("%s(): %s-%d>%s-%d: %s\n", __func__, src_addr, src_ssid, dst_addr, dst_ssid, description); - - switch (frame_type) { - - case frame_type_S_RR: // Receive Ready - System Ready To Receive - case frame_type_S_RNR: // Receive Not Ready - TNC Buffer Full - case frame_type_S_REJ: // Reject Frame - Out of Sequence or Duplicate - case frame_type_S_SREJ: // Selective Reject - Request single frame repeat - - // S frames (RR, RNR, REJ, SREJ), mod 8, have control N(R) P/F S S 0 1 - // These are mapped into P/F N(R) C S S - // Bit 6 is not mentioned in documentation but it is used for P/F for the other frame types. - // C is copied from the C bit in the destination addr. - // C from source is not used here. Reception assumes it is the opposite. - // PID is set to 0, meaning none, for S frames. - - SET_UI(hdr, 0); - SET_PID(hdr, 0); - SET_CONTROL(hdr, (pf << 6) | (nr << 3) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); - - // This gets OR'ed into the above. - switch (frame_type) { - case frame_type_S_RR: SET_CONTROL(hdr, 0); break; - case frame_type_S_RNR: SET_CONTROL(hdr, 1); break; - case frame_type_S_REJ: SET_CONTROL(hdr, 2); break; - case frame_type_S_SREJ: SET_CONTROL(hdr, 3); break; - default: break; - } - - break; - - case frame_type_U_SABM: // Set Async Balanced Mode - case frame_type_U_DISC: // Disconnect - case frame_type_U_DM: // Disconnect Mode - case frame_type_U_UA: // Unnumbered Acknowledge - case frame_type_U_FRMR: // Frame Reject - case frame_type_U_UI: // Unnumbered Information - case frame_type_U_XID: // Exchange Identification - case frame_type_U_TEST: // Test - - // The encoding allows only 3 bits for frame type and SABME got left out. - // Control format: P/F opcode[3] C n/a n/a - // The grayed out n/a bits are observed as 00 in the example. - // The header UI field must also be set for UI frames. - // PID is set to 1 for all U frames other than UI. - - if (frame_type == frame_type_U_UI) { - SET_UI(hdr, 1); // I guess this is how we distinguish 'I' and 'UI' - // on the receiving end. - int pid = encode_pid(pp); - if (pid < 0) return (-1); - SET_PID(hdr, pid); - } - else { - SET_PID(hdr, 1); // 1 for 'U' other than 'UI'. - } - - // Each of the destination and source addresses has a "C" bit. - // They should normally have the opposite setting. - // IL2P has only a single bit to represent 4 possbilities. - // - // dst src il2p meaning - // --- --- ---- ------- - // 0 0 0 Not valid (earlier protocol version) - // 1 0 1 Command (v2) - // 0 1 0 Response (v2) - // 1 1 1 Not valid (earlier protocol version) - // - // APRS does not mention how to set these bits and all 4 combinations - // are seen in the wild. Apparently these are ignored on receive and no - // one cares. Here we copy from the C bit in the destination address. - // It should be noted that the case of both C bits being the same can't - // be represented so the il2p encode/decode bit not produce exactly the - // same bits. We see this in the second example in the protocol spec. - // The original UI frame has both C bits of 0 so it is received as a response. - - SET_CONTROL(hdr, (pf << 6) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); - - // This gets OR'ed into the above. - switch (frame_type) { - case frame_type_U_SABM: SET_CONTROL(hdr, 0 << 3); break; - case frame_type_U_DISC: SET_CONTROL(hdr, 1 << 3); break; - case frame_type_U_DM: SET_CONTROL(hdr, 2 << 3); break; - case frame_type_U_UA: SET_CONTROL(hdr, 3 << 3); break; - case frame_type_U_FRMR: SET_CONTROL(hdr, 4 << 3); break; - case frame_type_U_UI: SET_CONTROL(hdr, 5 << 3); break; - case frame_type_U_XID: SET_CONTROL(hdr, 6 << 3); break; - case frame_type_U_TEST: SET_CONTROL(hdr, 7 << 3); break; - default: break; - } - break; - - case frame_type_I: // Information - - // I frames (mod 8 only) - // encoded control: P/F N(R) N(S) - - SET_UI(hdr, 0); - - int pid2 = encode_pid(pp); - if (pid2 < 0) return (-1); - SET_PID(hdr, pid2); - - SET_CONTROL(hdr, (pf << 6) | (nr << 3) | ns); - break; - - case frame_type_U_SABME: // Set Async Balanced Mode, Extended - case frame_type_U: // other Unnumbered, not used by AX.25. - case frame_not_AX25: // Could not get control byte from frame. - default: - - // Fall back to the header type 0 for these. - return (-1); - } - - // Common for all header type 1. - - // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] - - SET_FEC_LEVEL(hdr, max_fec); - SET_HDR_TYPE(hdr, 1); - - unsigned char *pinfo; - int info_len; - - info_len = ax25_get_info(pp, &pinfo); - if (info_len < 0 || info_len > IL2P_MAX_PAYLOAD_SIZE) { - return (-2); - } - - SET_PAYLOAD_BYTE_COUNT(hdr, info_len); - return (info_len); -} - - -// This should create a packet from the IL2P header. -// The information part will not be filled in. - -static void trim(char *stuff) -{ - char *p = stuff + strlen(stuff) - 1; - while (strlen(stuff) > 0 && (*p == ' ')) { - *p = '\0'; - p--; - } -} - - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_decode_header_type_1 - * - * Purpose: Attempt to convert type 1 header to a packet object. - * - * Inputs: hdr - IL2P header with no scrambling or parity symbols. - * - * num_sym_changed - Number of symbols changed by FEC in the header. - * Should be 0 or 1. - * - * Returns: Packet Object or NULL for failure. - * - * Description: A later step will process the payload for the information part. - * - *--------------------------------------------------------------------------------*/ - -packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed) -{ - - if (GET_HDR_TYPE(hdr) != 1) { - Debugprintf("IL2P Internal error. Should not be here: %s, when header type is 0.\n", __func__); - return (NULL); - } - - // First get the addresses including SSID. - - char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN]; - int num_addr = 2; - memset(addrs, 0, 2 * AX25_MAX_ADDR_LEN); - - // The IL2P header uses 2 parity symbols which means a single corrupted symbol (byte) - // can always be corrected. - // However, I have seen cases, where the error rate is very high, where the RS decoder - // thinks it found a valid code block by changing one symbol but it was the wrong one. - // The result is trash. This shows up as address fields like 'R&G4"A' and 'TEW\ !'. - // I added a sanity check here to catch characters other than upper case letters and digits. - // The frame should be rejected in this case. The question is whether to discard it - // silently or print a message so the user can see that something strange is happening? - // My current thinking is that it should be silently ignored if the header has been - // modified (correctee or more likely, made worse in this cases). - // If no changes were made, something weird is happening. We should mention it for - // troubleshooting rather than sweeping it under the rug. - - // The same thing has been observed with the payload, under very high error conditions, - // and max_fec==0. Here I don't see a good solution. AX.25 information can contain - // "binary" data so I'm not sure what sort of sanity check could be added. - // This was not observed with max_fec==1. If we make that the default, same as Nino TNC, - // it would be extremely extremely unlikely unless someone explicitly selects weaker FEC. - - // TODO: We could do something similar for header type 0. - // The address fields should be all binary zero values. - // Someone overly ambitious might check the addresses found in the first payload block. - - for (int i = 0; i <= 5; i++) { - addrs[AX25_DESTINATION][i] = sixbit_to_ascii(hdr[i] & 0x3f); - } - trim(addrs[AX25_DESTINATION]); - for (int i = 0; i < strlen(addrs[AX25_DESTINATION]); i++) { - if (!isupper(addrs[AX25_DESTINATION][i]) && !isdigit(addrs[AX25_DESTINATION][i])) { - if (num_sym_changed == 0) { - // This can pop up sporadically when receiving random noise. - // Would be better to show only when debug is enabled but variable not available here. - // TODO: For now we will just suppress it. - //text_color_set(DW_COLOR_ERROR); - //Debugprintf ("IL2P: Invalid character '%c' in destination address '%s'\n", addrs[AX25_DESTINATION][i], addrs[AX25_DESTINATION]); - } - return (NULL); - } - } - sprintf(addrs[AX25_DESTINATION] + strlen(addrs[AX25_DESTINATION]), "-%d", (hdr[12] >> 4) & 0xf); - - for (int i = 0; i <= 5; i++) { - addrs[AX25_SOURCE][i] = sixbit_to_ascii(hdr[i + 6] & 0x3f); - } - trim(addrs[AX25_SOURCE]); - for (int i = 0; i < strlen(addrs[AX25_SOURCE]); i++) { - if (!isupper(addrs[AX25_SOURCE][i]) && !isdigit(addrs[AX25_SOURCE][i])) { - if (num_sym_changed == 0) { - // This can pop up sporadically when receiving random noise. - // Would be better to show only when debug is enabled but variable not available here. - // TODO: For now we will just suppress it. - //text_color_set(DW_COLOR_ERROR); - //Debugprintf ("IL2P: Invalid character '%c' in source address '%s'\n", addrs[AX25_SOURCE][i], addrs[AX25_SOURCE]); - } - return (NULL); - } - } - sprintf(addrs[AX25_SOURCE] + strlen(addrs[AX25_SOURCE]), "-%d", hdr[12] & 0xf); - - // The PID field gives us the general type. - // 0 = 'S' frame. - // 1 = 'U' frame other than UI. - // others are either 'UI' or 'I' depending on the UI field. - - int pid = GET_PID(hdr); - int ui = GET_UI(hdr); - - if (pid == 0) { - - // 'S' frame. - // The control field contains: P/F N(R) C S S - - int control = GET_CONTROL(hdr); - cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; - ax25_frame_type_t ftype; - switch (control & 0x03) { - case 0: ftype = frame_type_S_RR; break; - case 1: ftype = frame_type_S_RNR; break; - case 2: ftype = frame_type_S_REJ; break; - default: ftype = frame_type_S_SREJ; break; - } - int modulo = 8; - int nr = (control >> 3) & 0x07; - int pf = (control >> 6) & 0x01; - unsigned char *pinfo = NULL; // Any info for SREJ will be added later. - int info_len = 0; - return (ax25_s_frame(addrs, num_addr, cr, ftype, modulo, nr, pf, pinfo, info_len)); - } - else if (pid == 1) { - - // 'U' frame other than 'UI'. - // The control field contains: P/F OPCODE{3) C x x - - int control = GET_CONTROL(hdr); - cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; - int axpid = 0; // unused for U other than UI. - ax25_frame_type_t ftype; - switch ((control >> 3) & 0x7) { - case 0: ftype = frame_type_U_SABM; break; - case 1: ftype = frame_type_U_DISC; break; - case 2: ftype = frame_type_U_DM; break; - case 3: ftype = frame_type_U_UA; break; - case 4: ftype = frame_type_U_FRMR; break; - case 5: ftype = frame_type_U_UI; axpid = 0xf0; break; // Should not happen with IL2P pid == 1. - case 6: ftype = frame_type_U_XID; break; - default: ftype = frame_type_U_TEST; break; - } - int pf = (control >> 6) & 0x01; - unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. - int info_len = 0; - return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); - } - else if (ui) { - - // 'UI' frame. - // The control field contains: P/F OPCODE{3) C x x - - int control = GET_CONTROL(hdr); - cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; - ax25_frame_type_t ftype = frame_type_U_UI; - int pf = (control >> 6) & 0x01; - int axpid = decode_pid(GET_PID(hdr)); - unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. - int info_len = 0; - return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); - } - else { - - // 'I' frame. - // The control field contains: P/F N(R) N(S) - - int control = GET_CONTROL(hdr); - cmdres_t cr = cr_cmd; // Always command. - int pf = (control >> 6) & 0x01; - int nr = (control >> 3) & 0x7; - int ns = control & 0x7; - int modulo = 8; - int axpid = decode_pid(GET_PID(hdr)); - unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. - int info_len = 0; - return (ax25_i_frame(addrs, num_addr, cr, modulo, nr, ns, pf, axpid, pinfo, info_len)); - } - return (NULL); // unreachable but avoid warning. - -} // end - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_type_0_header - * - * Purpose: Attempt to create type 0 header from packet object. - * - * Inputs: pp - Packet object. - * - * max_fec - 1 to use maximum FEC symbols, 0 for automatic. - * - * Outputs: hdr - IL2P header with no scrambling or parity symbols. - * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. - * - * Returns: Number of bytes for information part or -1 for failure. - * In case of failure, fall back to type 0 transparent encapsulation. - * - * Description: The type 0 header is used when it is not one of the restricted cases - * covered by the type 1 header. - * The AX.25 frame is put in the payload. - * This will cover: more than one address, mod 128 sequences, etc. - * - *--------------------------------------------------------------------------------*/ - -int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr) -{ - memset(hdr, 0, IL2P_HEADER_SIZE); - - // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] - - SET_FEC_LEVEL(hdr, max_fec); - SET_HDR_TYPE(hdr, 0); - - int frame_len = ax25_get_frame_len(pp); - - if (frame_len < 14 || frame_len > IL2P_MAX_PAYLOAD_SIZE) { - return (-2); - } - - SET_PAYLOAD_BYTE_COUNT(hdr, frame_len); - return (frame_len); -} - - -/*********************************************************************************** - * - * Name: il2p_get_header_attributes - * - * Purpose: Extract a few attributes from an IL2p header. - * - * Inputs: hdr - IL2P header structure. - * - * Outputs: hdr_type - 0 or 1. - * - * max_fec - 0 for automatic or 1 for fixed maximum size. - * - * Returns: Payload byte count. (actual payload size, not the larger encoded format) - * - ***********************************************************************************/ - - -int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec) -{ - *hdr_type = GET_HDR_TYPE(hdr); - *max_fec = GET_FEC_LEVEL(hdr); - return(GET_PAYLOAD_BYTE_COUNT(hdr)); -} - - -/*********************************************************************************** - * - * Name: il2p_clarify_header - * - * Purpose: Convert received header to usable form. - * This involves RS FEC then descrambling. - * - * Inputs: rec_hdr - Header as received over the radio. - * - * Outputs: corrected_descrambled_hdr - After RS FEC and unscrambling. - * - * Returns: Number of symbols that were corrected: - * 0 = No errors - * 1 = Single symbol corrected. - * <0 = Unable to obtain good header. - * - ***********************************************************************************/ - -int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr) -{ - unsigned char corrected[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; - - int e = il2p_decode_rs(rec_hdr, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, corrected); - - il2p_descramble_block(corrected, corrected_descrambled_hdr, IL2P_HEADER_SIZE); - - return (e); -} - -// end il2p_header.c - - -/*-------------------------------------------------------------------------------- - * - * File: il2p_payload.c - * - * Purpose: Functions dealing with the payload. - * - *--------------------------------------------------------------------------------*/ - - - /*-------------------------------------------------------------------------------- - * - * Function: il2p_payload_compute - * - * Purpose: Compute number and sizes of data blocks based on total size. - * - * Inputs: payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) - * max_fec true for 16 parity symbols, false for automatic. - * - * Outputs: *p Payload block sizes and counts. - * Number of parity symbols per block. - * - * Returns: Number of bytes in the encoded format. - * Could be 0 for no payload blocks. - * -1 for error (i.e. invalid unencoded size: <0 or >1023) - * - *--------------------------------------------------------------------------------*/ - -int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec) -{ - memset(p, 0, sizeof(il2p_payload_properties_t)); - - if (payload_size < 0 || payload_size > IL2P_MAX_PAYLOAD_SIZE) { - return (-1); - } - if (payload_size == 0) { - return (0); - } - - if (max_fec) { - p->payload_byte_count = payload_size; - p->payload_block_count = (p->payload_byte_count + 238) / 239; - p->small_block_size = p->payload_byte_count / p->payload_block_count; - p->large_block_size = p->small_block_size + 1; - p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); - p->small_block_count = p->payload_block_count - p->large_block_count; - p->parity_symbols_per_block = 16; - } - else { - p->payload_byte_count = payload_size; - p->payload_block_count = (p->payload_byte_count + 246) / 247; - p->small_block_size = p->payload_byte_count / p->payload_block_count; - p->large_block_size = p->small_block_size + 1; - p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); - p->small_block_count = p->payload_block_count - p->large_block_count; - //p->parity_symbols_per_block = (p->small_block_size / 32) + 2; // Looks like error in documentation - - // It would work if the number of parity symbols was based on large block size. - - if (p->small_block_size <= 61) p->parity_symbols_per_block = 2; - else if (p->small_block_size <= 123) p->parity_symbols_per_block = 4; - else if (p->small_block_size <= 185) p->parity_symbols_per_block = 6; - else if (p->small_block_size <= 247) p->parity_symbols_per_block = 8; - else { - // Should not happen. But just in case... - Debugprintf("IL2P parity symbol per payload block error. small_block_size = %d\n", p->small_block_size); - return (-1); - } - } - - // Return the total size for the encoded format. - - return (p->small_block_count * (p->small_block_size + p->parity_symbols_per_block) + - p->large_block_count * (p->large_block_size + p->parity_symbols_per_block)); - -} // end il2p_payload_compute - - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_encode_payload - * - * Purpose: Split payload into multiple blocks such that each set - * of data and parity symbols fit into a 255 byte RS block. - * - * Inputs: *payload Array of bytes. - * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) - * max_fec true for 16 parity symbols, false for automatic. - * - * Outputs: *enc Encoded payload for transmission. - * Up to IL2P_MAX_ENCODED_SIZE bytes. - * - * Returns: -1 for error (i.e. invalid size) - * 0 for no blocks. (i.e. size zero) - * Number of bytes generated. Maximum IL2P_MAX_ENCODED_SIZE. - * - * Note: I interpreted the protocol spec as saying the LFSR state is retained - * between data blocks. During interoperability testing, I found that - * was not the case. It is reset for each data block. - * - *--------------------------------------------------------------------------------*/ - - -int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc) -{ - if (payload_size > IL2P_MAX_PAYLOAD_SIZE) return (-1); - if (payload_size == 0) return (0); - - // Determine number of blocks and sizes. - - il2p_payload_properties_t ipp; - int e; - e = il2p_payload_compute(&ipp, payload_size, max_fec); - if (e <= 0) { - return (e); - } - - unsigned char *pin = payload; - unsigned char *pout = enc; - int encoded_length = 0; - unsigned char scram[256]; - unsigned char parity[IL2P_MAX_PARITY_SYMBOLS]; - - // First the large blocks. - - for (int b = 0; b < ipp.large_block_count; b++) { - - il2p_scramble_block(pin, scram, ipp.large_block_size); - memcpy(pout, scram, ipp.large_block_size); - pin += ipp.large_block_size; - pout += ipp.large_block_size; - encoded_length += ipp.large_block_size; - il2p_encode_rs(scram, ipp.large_block_size, ipp.parity_symbols_per_block, parity); - memcpy(pout, parity, ipp.parity_symbols_per_block); - pout += ipp.parity_symbols_per_block; - encoded_length += ipp.parity_symbols_per_block; - } - - // Then the small blocks. - - for (int b = 0; b < ipp.small_block_count; b++) { - - il2p_scramble_block(pin, scram, ipp.small_block_size); - memcpy(pout, scram, ipp.small_block_size); - pin += ipp.small_block_size; - pout += ipp.small_block_size; - encoded_length += ipp.small_block_size; - il2p_encode_rs(scram, ipp.small_block_size, ipp.parity_symbols_per_block, parity); - memcpy(pout, parity, ipp.parity_symbols_per_block); - pout += ipp.parity_symbols_per_block; - encoded_length += ipp.parity_symbols_per_block; - } - - return (encoded_length); - -} // end il2p_encode_payload - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_decode_payload - * - * Purpose: Extract original data from encoded payload. - * - * Inputs: received Array of bytes. Size is unknown but in practice it - * must not exceed IL2P_MAX_ENCODED_SIZE. - * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) - * Expected result size based on header. - * max_fec true for 16 parity symbols, false for automatic. - * - * Outputs: payload_out Recovered payload. - * - * In/Out: symbols_corrected Number of symbols corrected. - * - * - * Returns: Number of bytes extracted. Should be same as payload_size going in. - * -3 for unexpected internal inconsistency. - * -2 for unable to recover from signal corruption. - * -1 for invalid size. - * 0 for no blocks. (i.e. size zero) - * - * Description: Each block is scrambled separately but the LSFR state is carried - * from the first payload block to the next. - * - *--------------------------------------------------------------------------------*/ - -int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected) -{ - // Determine number of blocks and sizes. - - il2p_payload_properties_t ipp; - int e; - e = il2p_payload_compute(&ipp, payload_size, max_fec); - if (e <= 0) { - return (e); - } - - unsigned char *pin = received; - unsigned char *pout = payload_out; - int decoded_length = 0; - int failed = 0; - - // First the large blocks. - - for (int b = 0; b < ipp.large_block_count; b++) { - unsigned char corrected_block[255]; - int e = il2p_decode_rs(pin, ipp.large_block_size, ipp.parity_symbols_per_block, corrected_block); - - // Debugprintf ("%s:%d: large block decode_rs returned status = %d\n", __FILE__, __LINE__, e); - - if (e < 0) failed = 1; - *symbols_corrected += e; - - il2p_descramble_block(corrected_block, pout, ipp.large_block_size); - - if (il2p_get_debug() >= 2) { - - Debugprintf("Descrambled large payload block, %d bytes:\n", ipp.large_block_size); - fx_hex_dump(pout, ipp.large_block_size); - } - - pin += ipp.large_block_size + ipp.parity_symbols_per_block; - pout += ipp.large_block_size; - decoded_length += ipp.large_block_size; - } - - // Then the small blocks. - - for (int b = 0; b < ipp.small_block_count; b++) { - unsigned char corrected_block[255]; - int e = il2p_decode_rs(pin, ipp.small_block_size, ipp.parity_symbols_per_block, corrected_block); - - // Debugprintf ("%s:%d: small block decode_rs returned status = %d\n", __FILE__, __LINE__, e); - - if (e < 0) failed = 1; - *symbols_corrected += e; - - il2p_descramble_block(corrected_block, pout, ipp.small_block_size); - - if (il2p_get_debug() >= 2) { - - Debugprintf("Descrambled small payload block, %d bytes:\n", ipp.small_block_size); - fx_hex_dump(pout, ipp.small_block_size); - } - - pin += ipp.small_block_size + ipp.parity_symbols_per_block; - pout += ipp.small_block_size; - decoded_length += ipp.small_block_size; - } - - if (failed) { - //Debugprintf ("%s:%d: failed = %0x\n", __FILE__, __LINE__, failed); - return (-2); - } - - if (decoded_length != payload_size) { - Debugprintf("IL2P Internal error: decoded_length = %d, payload_size = %d\n", decoded_length, payload_size); - return (-3); - } - - return (decoded_length); - -} // end il2p_decode_payload - -// end il2p_payload.c - - - -struct il2p_context_s { - - enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_DECODE } state; - - unsigned int acc; // Accumulate most recent 24 bits for sync word matching. - // Lower 8 bits are also used for accumulating bytes for - // the header and payload. - - int bc; // Bit counter so we know when a complete byte has been accumulated. - - int polarity; // 1 if opposite of expected polarity. - - unsigned char shdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; - // Scrambled header as received over the radio. Includes parity. - int hc; // Number if bytes placed in above. - - unsigned char uhdr[IL2P_HEADER_SIZE]; // Header after FEC and unscrambling. - - int eplen; // Encoded payload length. This is not the nuumber from - // from the header but rather the number of encoded bytes to gather. - - unsigned char spayload[IL2P_MAX_ENCODED_PAYLOAD_SIZE]; - // Scrambled and encoded payload as received over the radio. - int pc; // Number of bytes placed in above. - - int corrected; // Number of symbols corrected by RS FEC. -}; - -static struct il2p_context_s *il2p_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; - - - -/*********************************************************************************** - * - * Name: il2p_rec_bit - * - * Purpose: Extract FX.25 packets from a stream of bits. - * - * Inputs: chan - Channel number. - * - * subchan - This allows multiple demodulators per channel. - * - * slice - Allows multiple slicers per demodulator (subchannel). - * - * dbit - One bit from the received data stream. - * - * Description: This is called once for each received bit. - * For each valid packet, process_rec_frame() is called for further processing. - * It can gather multiple candidates from different parallel demodulators - * ("subchannels") and slicers, then decide which one is the best. - * - ***********************************************************************************/ - -int centreFreq[4] = { 0, 0, 0, 0 }; - -void il2p_rec_bit(int chan, int subchan, int slice, int dbit) -{ - // Allocate context blocks only as needed. - - if (dbit) - dbit = 1; - - struct il2p_context_s *F = il2p_context[chan][subchan][slice]; - if (F == NULL) { - //assert(chan >= 0 && chan < MAX_CHANS); - //assert(subchan >= 0 && subchan < MAX_SUBCHANS); - //assert(slice >= 0 && slice < MAX_SLICERS); - F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s)); - //assert(F != NULL); - memset(F, 0, sizeof(struct il2p_context_s)); - } - - // Accumulate most recent 24 bits received. Most recent is LSB. - - F->acc = ((F->acc << 1) | (dbit & 1)) & 0x00ffffff; - - // State machine to look for sync word then gather appropriate number of header and payload bytes. - - switch (F->state) { - - case IL2P_SEARCHING: // Searching for the sync word. - - if (__builtin_popcount(F->acc ^ IL2P_SYNC_WORD) <= 1) { // allow single bit mismatch - //text_color_set (DW_COLOR_INFO); - //Debugprintf ("IL2P header has normal polarity\n"); - F->polarity = 0; - F->state = IL2P_HEADER; - F->bc = 0; - F->hc = 0; - - // Determine Centre Freq - - centreFreq[chan] = GuessCentreFreq(chan); - } - else if (__builtin_popcount((~F->acc & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) { - // FIXME - this pops up occasionally with random noise. Find better way to convey information. - // This also happens for each slicer - to noisy. - //Debugprintf ("IL2P header has reverse polarity\n"); - F->polarity = 1; - F->state = IL2P_HEADER; - F->bc = 0; - F->hc = 0; - centreFreq[chan] = GuessCentreFreq(chan); - } - - break; - - case IL2P_HEADER: // Gathering the header. - - F->bc++; - if (F->bc == 8) { // full byte has been collected. - F->bc = 0; - if (!F->polarity) { - F->shdr[F->hc++] = F->acc & 0xff; - } - else { - F->shdr[F->hc++] = (~F->acc) & 0xff; - } - if (F->hc == IL2P_HEADER_SIZE + IL2P_HEADER_PARITY) { // Have all of header - - //if (il2p_get_debug() >= 1) - //{ - // Debugprintf("IL2P header as received [%d.%d.%d]:\n", chan, subchan, slice); - // fx_hex_dump(F->shdr, IL2P_HEADER_SIZE + IL2P_HEADER_PARITY); - //} - - // Fix any errors and descramble. - F->corrected = il2p_clarify_header(F->shdr, F->uhdr); - - if (F->corrected >= 0) { // Good header. - // How much payload is expected? - il2p_payload_properties_t plprop; - int hdr_type, max_fec; - int len = il2p_get_header_attributes(F->uhdr, &hdr_type, &max_fec); - - F->eplen = il2p_payload_compute(&plprop, len, max_fec); - - if (il2p_get_debug() >= 1) - { - Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec); - Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len); - Debugprintf("%d small blocks of %d and %d large blocks of %d. %d parity symbols per block", - plprop.small_block_count, plprop.small_block_size, - plprop.large_block_count, plprop.large_block_size, plprop.parity_symbols_per_block); - } - - if (F->eplen >= 1) { // Need to gather payload. - F->pc = 0; - F->state = IL2P_PAYLOAD; - } - else if (F->eplen == 0) { // No payload. - F->pc = 0; - F->state = IL2P_DECODE; - } - else { // Error. - - if (il2p_get_debug() >= 1) { - Debugprintf("IL2P header INVALID.\n"); - } - - F->state = IL2P_SEARCHING; - } - } // good header after FEC. - else { - F->state = IL2P_SEARCHING; // Header failed FEC check. - } - } // entire header has been collected. - } // full byte collected. - break; - - case IL2P_PAYLOAD: // Gathering the payload, if any. - - F->bc++; - if (F->bc == 8) { // full byte has been collected. - F->bc = 0; - if (!F->polarity) { - F->spayload[F->pc++] = F->acc & 0xff; - } - else { - F->spayload[F->pc++] = (~F->acc) & 0xff; - } - if (F->pc == F->eplen) { - - // TODO?: for symmetry it seems like we should clarify the payload before combining. - - F->state = IL2P_DECODE; - } - } - break; - - case IL2P_DECODE: - // We get here after a good header and any payload has been collected. - // Processing is delayed by one bit but I think it makes the logic cleaner. - // During unit testing be sure to send an extra bit to flush it out at the end. - - // in uhdr[IL2P_HEADER_SIZE]; // Header after FEC and descrambling. - - // TODO?: for symmetry, we might decode the payload here and later build the frame. - - { - packet_t pp = il2p_decode_header_payload(F->uhdr, F->spayload, &(F->corrected)); - - if (il2p_get_debug() >= 1) - { - if (pp == NULL) - { - // Most likely too many FEC errors. - Debugprintf("FAILED to construct frame in %s.\n", __func__); - } - } - - if (pp != NULL) { - alevel_t alevel = demod_get_audio_level(chan, subchan); - retry_t retries = F->corrected; - int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. - // Currently this just means that a FEC mode was used. - - // TODO: Could we put last 3 arguments in packet object rather than passing around separately? - - multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]); - } - } // end block for local variables. - - if (il2p_get_debug() >= 1) { - - Debugprintf("-----"); - } - - F->state = IL2P_SEARCHING; - break; - - } // end of switch - -} // end il2p_rec_bit - - - - - - - -// Scramble bits for il2p transmit. - -// Note that there is a delay of 5 until the first bit comes out. -// So we need to need to ignore the first 5 out and stick in -// an extra 5 filler bits to flush at the end. - -#define INIT_TX_LSFR 0x00f - -static inline int scramble_bit(int in, int *state) -{ - int out = ((*state >> 4) ^ *state) & 1; - *state = ((((in ^ *state) & 1) << 9) | (*state ^ ((*state & 1) << 4))) >> 1; - return (out); -} - - -// Undo data scrambling for il2p receive. - -#define INIT_RX_LSFR 0x1f0 - -static inline int descramble_bit(int in, int *state) -{ - int out = (in ^ *state) & 1; - *state = ((*state >> 1) | ((in & 1) << 8)) ^ ((in & 1) << 3); - return (out); -} - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_scramble_block - * - * Purpose: Scramble a block before adding RS parity. - * - * Inputs: in Array of bytes. - * len Number of bytes both in and out. - * - * Outputs: out Array of bytes. - * - *--------------------------------------------------------------------------------*/ - -void il2p_scramble_block(unsigned char *in, unsigned char *out, int len) -{ - int tx_lfsr_state = INIT_TX_LSFR; - - memset(out, 0, len); - - int skipping = 1; // Discard the first 5 out. - int ob = 0; // Index to output byte. - int om = 0x80; // Output bit mask; - for (int ib = 0; ib < len; ib++) { - for (int im = 0x80; im != 0; im >>= 1) { - int s = scramble_bit((in[ib] & im) != 0, &tx_lfsr_state); - if (ib == 0 && im == 0x04) skipping = 0; - if (!skipping) { - if (s) { - out[ob] |= om; - } - om >>= 1; - if (om == 0) { - om = 0x80; - ob++; - } - } - } - } - // Flush it. - - // This is a relic from when I thought the state would need to - // be passed along for the next block. - // Preserve the LSFR state from before flushing. - // This might be needed as the initial state for later payload blocks. - int x = tx_lfsr_state; - for (int n = 0; n < 5; n++) { - int s = scramble_bit(0, &x); - if (s) { - out[ob] |= om; - } - om >>= 1; - if (om == 0) { - om = 0x80; - ob++; - } - } - -} // end il2p_scramble_block - - - -/*-------------------------------------------------------------------------------- - * - * Function: il2p_descramble_block - * - * Purpose: Descramble a block after removing RS parity. - * - * Inputs: in Array of bytes. - * len Number of bytes both in and out. - * - * Outputs: out Array of bytes. - * - *--------------------------------------------------------------------------------*/ - -void il2p_descramble_block(unsigned char *in, unsigned char *out, int len) -{ - int rx_lfsr_state = INIT_RX_LSFR; - - memset(out, 0, len); - - for (int b = 0; b < len; b++) { - for (int m = 0x80; m != 0; m >>= 1) { - int d = descramble_bit((in[b] & m) != 0, &rx_lfsr_state); - if (d) { - out[b] |= m; - } - } - } -} - -// end il2p_scramble.c - - - - -static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "il2p_send_frame" - -static void send_bytes(int chan, unsigned char *b, int count, int polarity); -static void send_bit(int chan, int b, int polarity); - - - -/*------------------------------------------------------------- - * - * Name: il2p_send_frame - * - * Purpose: Convert frames to a stream of bits in IL2P format. - * - * Inputs: chan - Audio channel number, 0 = first. - * - * pp - Pointer to packet object. - * - * max_fec - 1 to force 16 parity symbols for each payload block. - * 0 for automatic depending on block size. - * - * polarity - 0 for normal. 1 to invert signal. - * 2 special case for testing - introduce some errors to test FEC. - * - * Outputs: Bits are shipped out by calling tone_gen_put_bit(). - * - * Returns: Number of bits sent including - * - Preamble (01010101...) - * - 3 byte Sync Word. - * - 15 bytes for Header. - * - Optional payload. - * The required time can be calculated by dividing this - * number by the transmit rate of bits/sec. - * -1 is returned for failure. - * - * Description: Generate an IL2P encoded frame. - * - * Assumptions: It is assumed that the tone_gen module has been - * properly initialized so that bits sent with - * tone_gen_put_bit() are processed correctly. - * - * Errors: Return -1 for error. Probably frame too large. - * - * Note: Inconsistency here. ax25 version has just a byte array - * and length going in. Here we need the full packet object. - * - *--------------------------------------------------------------*/ - -string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity) -{ - unsigned char encoded[IL2P_MAX_PACKET_SIZE]; - string * packet = newString(); - int preamblecount; - unsigned char preamble[1024]; - - - encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff; - encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff; - encoded[2] = (IL2P_SYNC_WORD) & 0xff; - - int elen = il2p_encode_frame(pp, max_fec, encoded + IL2P_SYNC_WORD_SIZE); - if (elen <= 0) { - Debugprintf("IL2P: Unable to encode frame into IL2P.\n"); - return (packet); - } - - elen += IL2P_SYNC_WORD_SIZE; - - number_of_bits_sent[chan] = 0; - - if (il2p_get_debug() >= 1) { - Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen); -// fx_hex_dump(encoded, elen); - } - - // Send bits to modulator. - - // Try using preaamble for txdelay - - preamblecount = (txdelay[chan] * tx_baudrate[chan]) / 8000; // 8 for bits, 1000 for mS - - if (preamblecount > 1024) - preamblecount = 1024; - - memset(preamble, IL2P_PREAMBLE, preamblecount); - - stringAdd(packet, preamble, preamblecount); - stringAdd(packet, encoded, elen); - - tx_fx25_size[chan] = packet->Length * 8; - - return packet; -} - - - -// TX Code. Builds whole packet then sends a bit at a time - -#define TX_SILENCE 0 -#define TX_DELAY 1 -#define TX_TAIL 2 -#define TX_NO_DATA 3 -#define TX_FRAME 4 -#define TX_WAIT_BPF 5 - - -#define TX_BIT0 0 -#define TX_BIT1 1 -#define FRAME_EMPTY 0 -#define FRAME_FULL 1 -#define FRAME_NO_FRAME 2 -#define FRAME_NEW_FRAME 3 -#define BYTE_EMPTY 0 -#define BYTE_FULL 1 - -extern UCHAR tx_frame_status[5]; -extern UCHAR tx_byte_status[5]; -extern string * tx_data[5]; -extern int tx_data_len[5]; -extern UCHAR tx_bit_stream[5]; -extern UCHAR tx_bit_cnt[5]; -extern long tx_tail_cnt[5]; -extern BOOL tx_bs_bit[5]; - -string * fill_il2p_data(int snd_ch, string * data) -{ - string * result; - packet_t pp = ax25_new(); - - - // Call il2p_send_frame to build the bit stream - - pp->frame_len = data->Length - 2; // Included CRC - memcpy(pp->frame_data, data->Data, data->Length); - - result = il2p_send_frame(snd_ch, pp, 1, 0); - - return result; -} - - - -void il2p_get_new_frame(int snd_ch, TStringList * frame_stream) -{ - string * myTemp; - - tx_bs_bit[snd_ch] = 0; - tx_bit_cnt[snd_ch] = 0; - tx_fx25_size_cnt[snd_ch] = 0; - tx_fx25_size[snd_ch] = 1; - tx_frame_status[snd_ch] = FRAME_NEW_FRAME; - tx_byte_status[snd_ch] = BYTE_EMPTY; - - if (frame_stream->Count == 0) - tx_frame_status[snd_ch] = FRAME_NO_FRAME; - else - { - // We now pass control byte and ack bytes on front and pointer to socket on end if ackmode - - myTemp = Strings(frame_stream, 0); // get message - - if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE - { - // Save copy then copy data up 3 bytes - - Add(&KISS_acked[snd_ch], duplicateString(myTemp)); - - mydelete(myTemp, 0, 3); - myTemp->Length -= sizeof(void *); - } - else - { - // Just remove control - - mydelete(myTemp, 0, 1); - } - - AGW_AX25_frame_analiz(snd_ch, FALSE, myTemp); - put_frame(snd_ch, myTemp, "", TRUE, FALSE); - - tx_data[snd_ch] = fill_il2p_data(snd_ch, myTemp); - - Delete(frame_stream, 0); // This will invalidate temp - } -} - - - -// Original code - -/* -static void send_bytes(int chan, unsigned char *b, int count, int polarity) -{ - for (int j = 0; j < count; j++) { - unsigned int x = b[j]; - for (int k = 0; k < 8; k++) { - send_bit(chan, (x & 0x80) != 0, polarity); - x <<= 1; - } - } -} - -// NRZI would be applied for AX.25 but IL2P does not use it. -// However we do have an option to invert the signal. -// The direwolf receive implementation will automatically compensate -// for either polarity but other implementations might not. - -static void send_bit(int chan, int b, int polarity) -{ - tone_gen_put_bit(chan, (b ^ polarity) & 1); - number_of_bits_sent[chan]++; -} -*/ - - - - -int il2p_get_new_bit(int snd_ch, Byte bit) -{ - string *s; - - if (tx_frame_status[snd_ch] == FRAME_EMPTY) - { - il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); - if (tx_frame_status[snd_ch] == FRAME_NEW_FRAME) - tx_frame_status[snd_ch] = FRAME_FULL; - } - - if (tx_frame_status[snd_ch] == FRAME_FULL) - { - if (tx_byte_status[snd_ch] == BYTE_EMPTY) - { - if (tx_data[snd_ch]->Length) - { - s = tx_data[snd_ch]; - - tx_bit_stream[snd_ch] = s->Data[0]; - tx_frame_status[snd_ch] = FRAME_FULL; - tx_byte_status[snd_ch] = BYTE_FULL; - tx_bit_cnt[snd_ch] = 0; - mydelete(tx_data[snd_ch], 0, 1); - } - else - tx_frame_status[snd_ch] = FRAME_EMPTY; - } - if (tx_byte_status[snd_ch] == BYTE_FULL) - { - // il2p sends high order bit first - - bit = tx_bit_stream[snd_ch] >> 7; // top bit to bottom - - tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] << 1; - tx_bit_cnt[snd_ch]++; - tx_fx25_size_cnt[snd_ch]++; - if (tx_bit_cnt[snd_ch] >= 8) - tx_byte_status[snd_ch] = BYTE_EMPTY; - if (tx_fx25_size_cnt[snd_ch] == tx_fx25_size[snd_ch]) - tx_frame_status[snd_ch] = FRAME_EMPTY; - } - } - - if (tx_frame_status[snd_ch] == FRAME_EMPTY) - { - il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); - - switch (tx_frame_status[snd_ch]) - { - case FRAME_NEW_FRAME: - tx_frame_status[snd_ch] = FRAME_FULL; - break; - - case FRAME_NO_FRAME: - tx_tail_cnt[snd_ch] = 0; - tx_frame_status[snd_ch] = FRAME_EMPTY; - tx_status[snd_ch] = TX_TAIL; - break; - } - } - return bit; -} - - -