diff --git a/KISSConfig.ui b/KISSConfig.ui index 3f4509a..8c54dfe 100644 --- a/KISSConfig.ui +++ b/KISSConfig.ui @@ -468,6 +468,35 @@ TXDelay + + + + 200 + 80 + 151 + 30 + + + + Open MH Window + + + + + + 390 + 83 + 20 + 20 + + + + Qt::RightToLeft + + + + + diff --git a/QtTermTCP.cpp b/QtTermTCP.cpp index 6f10b14..45fd43d 100644 --- a/QtTermTCP.cpp +++ b/QtTermTCP.cpp @@ -2,7 +2,7 @@ // Application icon design by Red PE1RRR -#define VersionString "0.0.0.78" +#define VersionString "0.0.0.79" // .12 Save font weight @@ -124,6 +124,10 @@ // Fix restoring monitor flags when connecting to current host +// .79 +// Add KISS MHEARD Window (Feb 2025) + + #define _CRT_SECURE_NO_WARNINGS #define UNUSED(x) (void)(x) @@ -328,6 +332,7 @@ extern "C" int KISSMonNodes; extern "C" int KISSListen; extern "C" int KISSChecksum; extern "C" int KISSAckMode; +extern "C" int KISSMH; extern "C" short txtail[5]; extern "C" short txdelay[5]; @@ -559,6 +564,7 @@ void AGWMonWindowClosing(Ui_ListenSession *Sess); void AGWWindowClosing(Ui_ListenSession *Sess); extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length); void closeSerialPort(); +int newMHWindow(QObject * parent, int Type, const char * Label); extern void initUTF8(); int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); @@ -736,12 +742,39 @@ void DoTermResize(Ui_ListenSession * Sess) } } + +extern "C" Ui_ListenSession * MHWindow; + bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) { // See if from a Listening Session Ui_ListenSession * Sess; + if (obj == MHWindow) + { + if (event->type() == QEvent::Resize) + { + QRect r = MHWindow->rect(); + + int H, Width, Border = 3; + + Width = r.width() - 6; + H = r.height() - 6; + + MHWindow->monWindow->setGeometry(QRect(Border, Border, Width, H)); + return true; + } + if (event->type() == QEvent::Close) + { + QSettings mysettings(GetConfPath(), QSettings::IniFormat); + mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); + SaveSettings(); + MHWindow = 0; + } + } + + for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); @@ -1336,6 +1369,12 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent) updateWindowMenu(); + if (KISSEnable && KISSMH) + { + newMHWindow(this, 0, "KISS MH"); + MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); + } + connectMenu = mymenuBar->addMenu(tr("&Connect")); actHost[16] = new QAction("AGW Connect", this); @@ -3604,6 +3643,7 @@ void GetSettings() KISSListen = settings->value("KISSListen", 1).toInt(); KISSChecksum = settings->value("KISSChecksum", 0).toInt(); KISSAckMode = settings->value("KISSAckMode", 0).toInt(); + KISSMH = settings->value("KISSMH", 1).toInt(); strcpy(KISSMYCALL, settings->value("MYCALL", "").toString().toUtf8()); strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8()); KISSPortNum = settings->value("KISSPort", 8100).toInt(); @@ -3837,6 +3877,7 @@ extern "C" void SaveSettings() settings->setValue("KISSListen", KISSListen); settings->setValue("KISSChecksum", KISSChecksum); settings->setValue("KISSAckMode", KISSAckMode); + settings->setValue("KISSMH", KISSMH); settings->setValue("MYCALL", KISSMYCALL); settings->setValue("KISSHost", KISSHost); settings->setValue("KISSMode", KISSMode); @@ -3921,6 +3962,10 @@ void QtTermTCP::closeEvent(QCloseEvent *event) #endif if (process) process->close(); + + if (MHWindow) + MHWindow->close(); + } } @@ -3962,6 +4007,11 @@ QtTermTCP::~QtTermTCP() mysettings.setValue("geometry", saveGeometry()); mysettings.setValue("windowState", saveState()); + if (MHWindow) + { + mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); + MHWindow->close(); + } SaveSettings(); } @@ -4117,6 +4167,7 @@ void QtTermTCP::KISSSlot() KISS->KISSListen->setChecked(KISSListen); KISS->KISSChecksum->setChecked(KISSChecksum); KISS->KISSACKMODE->setChecked(KISSAckMode); + KISS->KISSMH->setChecked(KISSMH); KISS->MYCALL->setText(KISSMYCALL); KISS->TXDELAY->setText(QString::number(txdelay[0])); @@ -4176,6 +4227,7 @@ void QtTermTCP::KISSaccept() KISSListen = KISS->KISSListen->isChecked(); KISSChecksum = KISS->KISSChecksum->isChecked(); KISSAckMode = KISS->KISSACKMODE->isChecked(); + KISSMH = KISS->KISSMH->isChecked(); actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line strcpy(KISSMYCALL, KISS->MYCALL->text().toUtf8().toUpper()); @@ -4231,6 +4283,26 @@ void QtTermTCP::KISSaccept() } } + if (KISSEnable == 0 && MHWindow) + { + MHWindow->close(); + MHWindow = 0; + } + + if (KISSEnable && KISSMH && MHWindow == 0) + { + newMHWindow(this, 0, "KISS MH"); + QSettings mysettings(GetConfPath(), QSettings::IniFormat); + MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); + } + + if (!KISSMH && MHWindow) + { + MHWindow->close(); + MHWindow = 0; + } + + delete(KISS); SaveSettings(); deviceUI->accept(); @@ -7988,3 +8060,106 @@ void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg) } +// Create MH Window + + + +int newMHWindow(QObject * parent, int Type, const char * Label) +{ + Ui_ListenSession * Sess = new(Ui_ListenSession); + + MHWindow = Sess; + + // Need to explicity initialise on Qt4 + + Sess->termWindow = NULL; + Sess->monWindow = NULL; + Sess->inputWindow = NULL; + + Sess->StackIndex = 0; + Sess->InputMode = 0; + Sess->SlowTimer = 0; + Sess->MonData = 0; + Sess->OutputSaveLen = 0; + Sess->MonSaveLen = 0; + Sess->PortMonString[0] = 0; + Sess->portmask = 0; + Sess->portmask = 1; + Sess->mtxparam = 1; + Sess->mlocaltime = 0; + Sess->mcomparam = 1; + Sess->monUI = 0; + Sess->MonitorNODES = 0; + Sess->MonitorColour = 1; + Sess->CurrentHost = 0; + + Sess->SessionType = Type; + Sess->clientSocket = NULL; + Sess->AGWSession = NULL; + Sess->AGWMonSession = NULL; + Sess->KISSSession = NULL; + Sess->KISSMode = 0; + Sess->TTActive = 0; + Sess->TTFlashToggle = 0; + Sess->pageBuffer[0] = 0; + Sess->Tab = 0; + + Sess->LogMonitor = false; + Sess->monSpan = (char *) ""; + Sess->monLogfile = nullptr; + Sess->sessNo = sessNo++; + + QSettings settings(GetConfPath(), QSettings::IniFormat); + +#ifdef ANDROID + QFont font = QFont(settings.value("FontFamily", "Driod Sans Mono").value(), + settings.value("PointSize", 12).toInt(), + settings.value("Weight", 50).toInt()); +#else + QFont font = QFont(settings.value("FontFamily", "Courier New").value(), + settings.value("PointSize", 10).toInt(), + settings.value("Weight", 50).toInt()); +#endif + + Sess->monWindow = new QTextEdit(Sess); + Sess->monWindow->setReadOnly(1); + Sess->monWindow->document()->setMaximumBlockCount(10000); + Sess->monWindow->setFont(font); + Sess->monWindow->setStyleSheet(monStyleSheet); + + Sess->setWindowTitle(Label); + + Sess->installEventFilter(mythis); + + Sess->show(); + + + + Sess->monWindow->setGeometry(QRect(2, 2, 400, 400)); + Sess->setGeometry(QRect(400, 400, 400, 400)); + + + QSize Size(800, 602); // Not actually used, but Event constructor needs it + + QResizeEvent event(Size, Size); + + QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window + + return true; +} + +extern "C" void WritetoMHWindow(char * Buffer) +{ + unsigned char Copy[8192]; + unsigned char * ptr1, *ptr2; + unsigned char Line[8192]; + unsigned char out[8192]; + int outlen; + + int num; + + if (MHWindow == NULL || MHWindow->monWindow == NULL) + return; + + MHWindow->monWindow->setText(Buffer); +} diff --git a/QtTermTCP.vcxproj.user b/QtTermTCP.vcxproj.user index 43079b7..56666e6 100644 --- a/QtTermTCP.vcxproj.user +++ b/QtTermTCP.vcxproj.user @@ -3,11 +3,12 @@ C:\DevProgs\BPQ32\Release WindowsLocalDebugger - C:\Dev\Msdev2005\projects\QT\QtTermTCP\Win32\Debug\QtTermTCP.exe + C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe C:\DevProgs\BPQ32\Release WindowsLocalDebugger + C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe 2022-05-19T07:28:47.9186341Z @@ -16,15 +17,15 @@ 2022-05-19T07:28:58.9302359Z - 2024-08-18T13:22:28.7149666Z + 2025-02-19T10:20:19.7224236Z - 2024-08-18T13:22:29.0403359Z + 2025-02-19T10:20:19.9860750Z - 2024-08-18T13:22:28.3840024Z + 2025-02-19T10:20:19.2704826Z - 2024-08-18T13:22:28.6207028Z + 2025-02-19T10:20:19.4132585Z \ No newline at end of file diff --git a/ax25.c b/ax25.c index 6e9f489..5858b5a 100644 --- a/ax25.c +++ b/ax25.c @@ -44,7 +44,7 @@ void decode_frame(Byte * frame, int len, Byte * path, string * data, void SetSessLabel(void * Sess, char * label); void setMenus(int State); - +void MHPROC(unsigned char * Packet, int Len); /* unit ax25; @@ -2626,6 +2626,8 @@ void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) TXMSG = newString(); stringAdd(TXMSG, &Msg[1], Len - 1); // include Control + MHPROC(TXMSG->Data, TXMSG->Length); + analiz_frame(Chan, TXMSG, socket, 0); free(TXMSG); @@ -3019,6 +3021,221 @@ char * frame_monitor(string * frame, char * code, int tx_stat) return FrameData; } +typedef struct _MHSTRUC +{ + UCHAR MHCALL[7]; + UCHAR MHDIGIS[7][8]; + time_t MHTIME; + int MHCOUNT; + unsigned char MHDIGI; + char MHFreq[12]; + char MHLocator[6]; +} MHSTRUC, *PMHSTRUC; + + +#define MHENTRIES 30 + +MHSTRUC MHEARD[(MHENTRIES + 1) * sizeof(MHSTRUC)] = { 0 }; + +int CompareCalls(UCHAR * c1, UCHAR * c2) +{ + // COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID + + if (memcmp(c1, c2, 6)) + return FALSE; // No Match + + if ((c1[6] & 0x1e) == (c2[6] & 0x1e)) + return TRUE; + + return FALSE; +} + +static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +void * MHWindow = 0; +void WritetoMHWindow(char * Buffer); +int KISSMH = 0; + +char * FormatMH(PMHSTRUC MH) +{ + struct tm * TM; + static char MHTime[50]; + time_t szClock; + char LOC[7]; + + memcpy(LOC, MH->MHLocator, 6); + LOC[6] = 0; + + szClock = MH->MHTIME; +// else +// szClock = time(NULL) - MH->MHTIME; + + TM = gmtime(&szClock); + + sprintf(MHTime, "%s %02d %.2d:%.2d:%.2d %s %s", + month[TM->tm_mon], TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC); + + return MHTime; +} + + + + +void MHPROC(unsigned char * Packet, int Len) +{ + PMHSTRUC MH = &MHEARD[0]; + PMHSTRUC MHBASE = MH; + int i; + int OldCount = 0; + char Freq[64] = ""; + char DIGI = '*'; + + MESSAGE Frame; + MESSAGE * Buffer = &Frame; + + memcpy(Buffer->DEST, Packet, Len); + + + // if port has a freq associated with it use it + + + // if (Buffer->ORIGIN[6] & 1) + DIGI = 0; // Don't think we want to do this + +// See if in list + + for (i = 0; i < MHENTRIES; i++) + { + if ((MH->MHCALL[0] == 0) || (CompareCalls(Buffer->ORIGIN, MH->MHCALL) && MH->MHDIGI == DIGI)) // Spare or our entry + { + OldCount = MH->MHCOUNT; + goto DoMove; + } + MH++; + } + + // TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP + + i = MHENTRIES - 1; + + // Move others down and add at front +DoMove: + if (i != 0) // First + memmove(MHBASE + 1, MHBASE, i * sizeof(MHSTRUC)); + + memcpy(MHBASE->MHCALL, Buffer->ORIGIN, 7 * 9); // Save Digis + MHBASE->MHDIGI = DIGI; + MHBASE->MHTIME = time(NULL); + MHBASE->MHCOUNT = ++OldCount; + strcpy(MHBASE->MHFreq, Freq); + MHBASE->MHLocator[0] = 0; + + if (MHWindow) + { + int count = MHENTRIES; + int n; + char Normcall[20]; + char From[10]; + char DigiList[100]; + char * Output; + int len; + char Digi = 0; + char MHPage[MHENTRIES * 100]; + char * Bufferptr = MHPage; + unsigned char * ptr; + + MH = &MHEARD[0]; + + // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find + // how many digis there are + + Bufferptr += sprintf(Bufferptr, "Callsign Last heard Pkts RX via Digi\r"); + Bufferptr += sprintf(Bufferptr, "\r"); + + while (count--) + { + if (MH->MHCALL[0] == 0) + break; + + Digi = 0; + + len = ConvFromAX25(MH->MHCALL, Normcall); + + Normcall[len++] = MH->MHDIGI; + Normcall[len++] = 0; + + n = 8; // Max number of digi-peaters + + ptr = &MH->MHCALL[6]; // End of Address bit + + Output = &DigiList[0]; + + if ((*ptr & 1) == 0) + { + // at least one digi + + strcpy(Output, "via "); + Output += 4; + + while ((*ptr & 1) == 0) + { + // MORE TO COME + + From[ConvFromAX25(ptr + 1, From)] = 0; + Output += sprintf((char *)Output, "%s", From); + + ptr += 7; + n--; + + if (n == 0) + break; + + // See if digi actioned - put a * on last actioned + + if (*ptr & 0x80) + { + if (*ptr & 1) // if last address, must need * + { + *(Output++) = '*'; + Digi = '*'; + } + + else + if ((ptr[7] & 0x80) == 0) // Repeased by next? + { + *(Output++) = '*'; // No, so need * + Digi = '*'; + } + + } + *(Output++) = ','; + } + *(--Output) = 0; // remove last comma + } + else + *(Output) = 0; + + // if we used a digi set * on call and display via string + + + if (Digi) + Normcall[len++] = Digi; + else + DigiList[0] = 0; // Dont show list if not used + + Normcall[len++] = 0; + + ptr = FormatMH(MH); + + Bufferptr += sprintf(Bufferptr, "%-10s %-10s %-10d %-30s\r", Normcall, ptr, MH->MHCOUNT, DigiList); + + MH++; + } + + WritetoMHWindow(MHPage); + } + return; +} diff --git a/debug/moc_predefs.h b/debug/moc_predefs.h index 8247e15..b90fa38 100644 --- a/debug/moc_predefs.h +++ b/debug/moc_predefs.h @@ -1,7 +1,7 @@ #define _MSC_EXTENSIONS #define _INTEGRAL_MAX_BITS 64 #define _MSC_VER 1916 -#define _MSC_FULL_VER 191627043 +#define _MSC_FULL_VER 191627051 #define _MSC_BUILD 0 #define _WIN32 #define _M_IX86 600 diff --git a/release/moc_predefs.h b/release/moc_predefs.h index b1c49a8..24cfab5 100644 --- a/release/moc_predefs.h +++ b/release/moc_predefs.h @@ -1,7 +1,7 @@ #define _MSC_EXTENSIONS #define _INTEGRAL_MAX_BITS 64 #define _MSC_VER 1916 -#define _MSC_FULL_VER 191627045 +#define _MSC_FULL_VER 191627051 #define _MSC_BUILD 0 #define _WIN32 #define _M_IX86 600